diff options
687 files changed, 18331 insertions, 11432 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1c87b0a76e..16b0512a88a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -156,7 +156,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -566,7 +566,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" @@ -705,7 +705,7 @@ jobs: run: src/ci/scripts/verify-stable-version-number.sh if: success() && !env.SKIP_JOB - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}" AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}" diff --git a/Cargo.lock b/Cargo.lock index bf31bf72d4c..b1bdaef81ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -266,9 +266,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" @@ -491,9 +491,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e" dependencies = [ "android-tzdata", "iana-time-zone", @@ -514,9 +514,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" dependencies = [ "clap_builder", "clap_derive", @@ -556,14 +556,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.3" +version = "4.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -590,7 +590,7 @@ dependencies = [ "regex", "rustc_tools_util", "serde", - "syn 2.0.55", + "syn 2.0.57", "tempfile", "termize", "tokio", @@ -634,7 +634,7 @@ dependencies = [ "itertools 0.12.1", "quine-mc_cluskey", "regex", - "regex-syntax 0.8.2", + "regex-syntax 0.8.3", "rustc-semver", "semver", "serde", @@ -948,7 +948,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -959,7 +959,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -974,7 +974,7 @@ version = "0.1.79" dependencies = [ "itertools 0.12.1", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1015,7 +1015,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1025,7 +1025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" dependencies = [ "derive_builder_core", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1048,7 +1048,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1137,7 +1137,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1483,7 +1483,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -1627,9 +1627,9 @@ dependencies = [ [[package]] name = "handlebars" -version = "5.1.0" +version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" dependencies = [ "log", "pest", @@ -1921,7 +1921,7 @@ checksum = "d2abdd3a62551e8337af119c5899e600ca0c88ec8f23a46c60ba216c803dcf1a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2076,9 +2076,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jemalloc-sys" @@ -2215,13 +2215,12 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" -version = "0.0.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.5.0", "libc", - "redox_syscall", ] [[package]] @@ -2422,9 +2421,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -2708,7 +2707,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2719,9 +2718,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.101" +version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", @@ -2901,7 +2900,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -2955,9 +2954,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -3109,9 +3108,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0" +checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", @@ -3207,9 +3206,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a18479200779601e498ada4e8c1e1f50e3ee19deb0259c25825a98b5603b2cb4" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", @@ -3271,9 +3270,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "remote-test-client" @@ -3671,6 +3670,7 @@ dependencies = [ "rustc_metadata", "rustc_middle", "rustc_query_system", + "rustc_sanitizers", "rustc_session", "rustc_span", "rustc_symbol_mangling", @@ -3939,7 +3939,7 @@ dependencies = [ "fluent-syntax", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "unic-langid", ] @@ -4074,7 +4074,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "synstructure", ] @@ -4220,7 +4220,7 @@ version = "0.0.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "synstructure", ] @@ -4560,6 +4560,21 @@ dependencies = [ ] [[package]] +name = "rustc_sanitizers" +version = "0.0.0" +dependencies = [ + "bitflags 2.5.0", + "rustc_data_structures", + "rustc_hir", + "rustc_middle", + "rustc_span", + "rustc_target", + "rustc_trait_selection", + "tracing", + "twox-hash", +] + +[[package]] name = "rustc_serialize" version = "0.0.0" dependencies = [ @@ -4634,7 +4649,6 @@ dependencies = [ name = "rustc_symbol_mangling" version = "0.0.0" dependencies = [ - "bitflags 2.5.0", "punycode", "rustc-demangle", "rustc_data_structures", @@ -4644,9 +4658,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", - "rustc_trait_selection", "tracing", - "twox-hash", ] [[package]] @@ -4851,7 +4863,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -4972,9 +4984,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "security-framework" -version = "2.9.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6" dependencies = [ "bitflags 1.3.2", "core-foundation", @@ -4985,9 +4997,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef" dependencies = [ "core-foundation-sys", "libc", @@ -5034,14 +5046,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "indexmap", "itoa", @@ -5341,9 +5353,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.55" +version = "2.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" +checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35" dependencies = [ "proc-macro2", "quote", @@ -5364,7 +5376,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -5530,7 +5542,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -5641,9 +5653,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.36.0" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ "backtrace", "bytes", @@ -5753,7 +5765,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -5959,7 +5971,7 @@ checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4" dependencies = [ "proc-macro-hack", "quote", - "syn 2.0.55", + "syn 2.0.57", "unic-langid-impl", ] @@ -6191,7 +6203,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "wasm-bindgen-shared", ] @@ -6225,7 +6237,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6316,7 +6328,7 @@ dependencies = [ "rayon", "serde", "serde_json", - "syn 2.0.55", + "syn 2.0.57", "windows-metadata", ] @@ -6570,7 +6582,7 @@ checksum = "9e6936f0cce458098a201c245a11bef556c6a0181129c7034d10d76d1ec3a2b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "synstructure", ] @@ -6591,7 +6603,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] @@ -6611,7 +6623,7 @@ checksum = "e6a647510471d372f2e6c2e6b7219e44d8c574d24fdc11c610a61455782f18c3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", "synstructure", ] @@ -6634,7 +6646,7 @@ checksum = "7b4e5997cbf58990550ef1f0e5124a05e47e1ebd33a84af25739be6031a62c20" dependencies = [ "proc-macro2", "quote", - "syn 2.0.55", + "syn 2.0.57", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e12c968e205..bbf4ecfe61d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,7 @@ adler.debug = 0 gimli.debug = 0 miniz_oxide.debug = 0 object.debug = 0 +rustc-demangle.debug = 0 # These are very thin wrappers around executing lld with the right binary name. # Basically nothing within them can go wrong without having been explicitly logged anyway. diff --git a/RELEASES.md b/RELEASES.md index f35dd27ec24..3bd638ff64c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,10 @@ +Version 1.77.2 (2024-04-09) +=========================== + +<a id="1.77.2"></a> + +- [CVE-2024-24576: fix escaping of Windows batch file arguments in `std::process::Command`](https://blog.rust-lang.org/2024/04/09/cve-2024-24576.html) + Version 1.77.1 (2024-03-28) =========================== diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index e29ef591bcb..63ce6685e43 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2152,6 +2152,9 @@ pub enum TyKind { MacCall(P<MacCall>), /// Placeholder for a `va_list`. CVarArgs, + /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZeroU32`, + /// just as part of the type system. + Pat(P<Ty>, P<Pat>), /// Sometimes we need a dummy value when no error has occurred. Dummy, /// Placeholder for a kind that has failed to be defined. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 7337b969242..da57def263d 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -502,6 +502,10 @@ pub fn noop_visit_ty<T: MutVisitor>(ty: &mut P<Ty>, vis: &mut T) { } TyKind::Tup(tys) => visit_thin_vec(tys, |ty| vis.visit_ty(ty)), TyKind::Paren(ty) => vis.visit_ty(ty), + TyKind::Pat(ty, pat) => { + vis.visit_ty(ty); + vis.visit_pat(pat); + } TyKind::Path(qself, path) => { vis.visit_qself(qself); vis.visit_path(path); diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index 18986fb7504..9e9ae52962d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -446,6 +446,10 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { } try_visit!(visitor.visit_path(path, typ.id)); } + TyKind::Pat(ty, pat) => { + try_visit!(visitor.visit_ty(ty)); + try_visit!(visitor.visit_pat(pat)); + } TyKind::Array(ty, length) => { try_visit!(visitor.visit_ty(ty)); try_visit!(visitor.visit_anon_const(length)); diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 1c34fd0afbb..4c552289a81 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -381,4 +381,8 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { ArrayLen::Body(..) => intravisit::walk_array_len(self, len), } } + + fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { + self.visit_pat(p) + } } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8cf347bfa96..5005c22d4cc 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1463,7 +1463,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } } - TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"), + TyKind::Pat(ty, pat) => hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_pat(pat)), + TyKind::MacCall(_) => { + span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now") + } TyKind::CVarArgs => { let guar = self.dcx().span_delayed_bug( t.span, diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 093a985495c..01addc8127e 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -346,7 +346,7 @@ impl<'a> AstValidator<'a> { in_impl: matches!(parent, TraitOrTraitImpl::TraitImpl { .. }), const_context_label: parent_constness, remove_const_sugg: ( - self.session.source_map().span_extend_while(span, |c| c == ' ').unwrap_or(span), + self.session.source_map().span_extend_while_whitespace(span), match parent_constness { Some(_) => rustc_errors::Applicability::MachineApplicable, None => rustc_errors::Applicability::MaybeIncorrect, diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 5912dd3f931..d7cd3efe408 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -332,6 +332,9 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { ast::TyKind::Never => { gate!(&self, never_type, ty.span, "the `!` type is experimental"); } + ast::TyKind::Pat(..) => { + gate!(&self, pattern_types, ty.span, "pattern types are unstable"); + } _ => {} } visit::walk_ty(self, ty) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3ea182c5867..51ccfe89fbd 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1188,6 +1188,11 @@ impl<'a> State<'a> { ast::TyKind::CVarArgs => { self.word("..."); } + ast::TyKind::Pat(ty, pat) => { + self.print_type(ty); + self.word(" is "); + self.print_pat(pat); + } } self.end(); } diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs index 31307ef1410..64726eacca7 100644 --- a/compiler/rustc_borrowck/src/consumers.rs +++ b/compiler/rustc_borrowck/src/consumers.rs @@ -4,7 +4,6 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::{IndexSlice, IndexVec}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::{Body, Promoted}; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::TyCtxt; use std::rc::Rc; @@ -106,7 +105,7 @@ pub fn get_body_with_borrowck_facts( options: ConsumerOptions, ) -> BodyWithBorrowckFacts<'_> { let (input_body, promoted) = tcx.mir_promoted(def); - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build(); let input_body: &Body<'_> = &input_body.borrow(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); *super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap() diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 4a5ba441878..7fbf4c47ec8 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -32,7 +32,6 @@ use rustc_infer::infer::{ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; @@ -126,7 +125,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { return tcx.arena.alloc(result); } - let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::bind(tcx, def)).build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(def).build(); let promoted: &IndexSlice<_, _> = &promoted.borrow(); let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0; debug!("mir_borrowck done"); @@ -1606,6 +1605,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(_) @@ -1648,6 +1648,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 63b80445817..9f0e54febe4 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -7,7 +7,6 @@ use rustc_infer::infer::TyCtxtInferExt as _; use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin}; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_macros::extension; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{GenericArgKind, GenericArgs}; @@ -133,6 +132,18 @@ impl<'tcx> RegionInferenceContext<'tcx> { let ty = infcx.infer_opaque_definition_from_instantiation(opaque_type_key, concrete_type); + + // Sometimes, when the hidden type is an inference variable, it can happen that + // the hidden type becomes the opaque type itself. In this case, this was an opaque + // usage of the opaque type and we can ignore it. This check is mirrored in typeck's + // writeback. + // FIXME(-Znext-solver): This should be unnecessary with the new solver. + if let ty::Alias(ty::Opaque, alias_ty) = ty.kind() + && alias_ty.def_id == opaque_type_key.def_id.to_def_id() + && alias_ty.args == opaque_type_key.args + { + continue; + } // Sometimes two opaque types are the same only after we remap the generic parameters // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)` // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that @@ -321,13 +332,13 @@ fn check_opaque_type_well_formed<'tcx>( parent_def_id = tcx.local_parent(parent_def_id); } - // FIXME(-Znext-solver): We probably should use `DefiningAnchor::Bind(&[])` + // FIXME(-Znext-solver): We probably should use `&[]` instead of // and prepopulate this `InferCtxt` with known opaque values, rather than - // using the `Bind` anchor here. For now it's fine. + // allowing opaque types to be defined and checking them after the fact. let infcx = tcx .infer_ctxt() .with_next_trait_solver(next_trait_solver) - .with_opaque_type_inference(DefiningAnchor::bind(tcx, parent_def_id)) + .with_opaque_type_inference(parent_def_id) .build(); let ocx = ObligationCtxt::new(&infcx); let identity_args = GenericArgs::identity_for_item(tcx, def_id); diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index f28b786e4f7..a950f10787b 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -39,6 +39,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx, locations.span(self.body))?; + if cfg!(debug_assertions) { + let data = self.infcx.take_and_reset_region_constraints(); + if !data.is_empty() { + panic!("leftover region constraints: {data:#?}"); + } + } debug!(?output, ?constraints); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 554dac0852f..1b4c6041294 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -46,6 +46,7 @@ mod format; mod format_foreign; mod global_allocator; mod log_syntax; +mod pattern_type; mod source_util; mod test; mod trace_macros; @@ -95,6 +96,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, option_env: env::expand_option_env, + pattern_type: pattern_type::expand, std_panic: edition_panic::expand_panic, stringify: source_util::expand_stringify, trace_macros: trace_macros::expand_trace_macros, diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs new file mode 100644 index 00000000000..54039c2c538 --- /dev/null +++ b/compiler/rustc_builtin_macros/src/pattern_type.rs @@ -0,0 +1,29 @@ +use rustc_ast::{ast, ptr::P, tokenstream::TokenStream, Pat, Ty}; +use rustc_errors::PResult; +use rustc_expand::base::{self, DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult}; +use rustc_span::{sym, Span}; + +pub fn expand<'cx>( + cx: &'cx mut ExtCtxt<'_>, + sp: Span, + tts: TokenStream, +) -> MacroExpanderResult<'cx> { + let (ty, pat) = match parse_pat_ty(cx, tts) { + Ok(parsed) => parsed, + Err(err) => { + return ExpandResult::Ready(DummyResult::any(sp, err.emit())); + } + }; + + ExpandResult::Ready(base::MacEager::ty(cx.ty(sp, ast::TyKind::Pat(ty, pat)))) +} + +fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P<Ty>, P<Pat>)> { + let mut parser = cx.new_parser_from_tts(stream); + + let ty = parser.parse_ty()?; + parser.eat_keyword(sym::is); + let pat = parser.parse_pat_no_top_alt(None, None)?; + + Ok((ty, pat)) +} diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 0aa2bae8f78..771e5b21958 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -267,7 +267,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { .generic_activity("codegen prelude") .run(|| crate::abi::codegen_fn_prelude(fx, start_block)); - for (bb, bb_data) in fx.mir.basic_blocks.iter_enumerated() { + for (bb, bb_data) in traversal::mono_reachable(fx.mir, fx.tcx, fx.instance) { let block = fx.get_block(bb); fx.bcx.switch_to_block(block); @@ -789,7 +789,7 @@ fn codegen_stmt<'tcx>( layout.offset_of_subfield(fx, fields.iter()).bytes() } NullOp::UbChecks => { - let val = fx.tcx.sess.opts.debug_assertions; + let val = fx.tcx.sess.ub_checks(); let val = CValue::by_val( fx.bcx.ins().iconst(types::I8, i64::try_from(val).unwrap()), fx.layout_of(fx.tcx.types.bool), diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 75268341a4f..e8c96486041 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -341,6 +341,8 @@ fn emit_cgu( object: Some(global_asm_object_file), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }), existing_work_product: None, }) @@ -378,7 +380,15 @@ fn emit_module( prof.artifact_size("object_file", &*name, file.metadata().unwrap().len()); - Ok(CompiledModule { name, kind, object: Some(tmp_file), dwarf_object: None, bytecode: None }) + Ok(CompiledModule { + name, + kind, + object: Some(tmp_file), + dwarf_object: None, + bytecode: None, + assembly: None, + llvm_ir: None, + }) } fn reuse_workproduct_for_cgu( @@ -426,6 +436,8 @@ fn reuse_workproduct_for_cgu( object: Some(obj_out_regular), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }, module_global_asm: has_global_asm.then(|| CompiledModule { name: cgu.name().to_string(), @@ -433,6 +445,8 @@ fn reuse_workproduct_for_cgu( object: Some(obj_out_global_asm), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }), existing_work_product: Some((cgu.work_product_id(), work_product)), }) @@ -678,6 +692,8 @@ pub(crate) fn run_aot( object: Some(tmp_file), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, }) } else { None diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs index 76a619a1af7..3ea5be1ee56 100644 --- a/compiler/rustc_codegen_gcc/src/back/write.rs +++ b/compiler/rustc_codegen_gcc/src/back/write.rs @@ -158,6 +158,8 @@ pub(crate) unsafe fn codegen( config.emit_obj != EmitObj::None, cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked, config.emit_bc, + config.emit_asm, + config.emit_ir, &cgcx.output_filenames, )) } diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 3fda59e8b52..bb5045ec872 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -28,6 +28,7 @@ rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_middle = { path = "../rustc_middle" } rustc_query_system = { path = "../rustc_query_system" } +rustc_sanitizers = { path = "../rustc_sanitizers" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index d2828669d43..f918facc86d 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -150,7 +150,10 @@ impl LlvmType for CastTarget { // Simplify to a single unit or an array if there's no prefix. // This produces the same layout, but using a simpler type. if self.prefix.iter().all(|x| x.is_none()) { - if rest_count == 1 { + // We can't do this if is_consecutive is set and the unit would get + // split on the target. Currently, this is only relevant for i128 + // registers. + if rest_count == 1 && (!self.rest.is_consecutive || self.rest.unit != Reg::i128()) { return rest_ll_unit; } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 06a681c24e6..e61af863dc0 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -608,7 +608,7 @@ pub(crate) fn run_pass_manager( "LTOPostLink".as_ptr().cast(), 11, ) { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( module.module_llvm.llmod(), llvm::LLVMModFlagBehavior::Error, c"LTOPostLink".as_ptr().cast(), diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 68ba8cbf7b7..49f9d7ddab6 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -880,6 +880,8 @@ pub(crate) unsafe fn codegen( config.emit_obj != EmitObj::None, dwarf_object_emitted, config.emit_bc, + config.emit_asm, + config.emit_ir, &cgcx.output_filenames, )) } diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 1a32958d362..b7235972204 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -20,12 +20,9 @@ use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout, }; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_sanitizers::{cfi, kcfi}; use rustc_session::config::OptLevel; use rustc_span::Span; -use rustc_symbol_mangling::typeid::{ - kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance, - TypeIdOptions, -}; use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange}; use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target}; use smallvec::SmallVec; @@ -1632,18 +1629,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { return; } - let mut options = TypeIdOptions::empty(); + let mut options = cfi::TypeIdOptions::empty(); if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { - options.insert(TypeIdOptions::GENERALIZE_POINTERS); + options.insert(cfi::TypeIdOptions::GENERALIZE_POINTERS); } if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { - options.insert(TypeIdOptions::NORMALIZE_INTEGERS); + options.insert(cfi::TypeIdOptions::NORMALIZE_INTEGERS); } let typeid = if let Some(instance) = instance { - typeid_for_instance(self.tcx, instance, options) + cfi::typeid_for_instance(self.tcx, instance, options) } else { - typeid_for_fnabi(self.tcx, fn_abi, options) + cfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap(); @@ -1680,18 +1677,18 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { return None; } - let mut options = TypeIdOptions::empty(); + let mut options = kcfi::TypeIdOptions::empty(); if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { - options.insert(TypeIdOptions::GENERALIZE_POINTERS); + options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS); } if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { - options.insert(TypeIdOptions::NORMALIZE_INTEGERS); + options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS); } let kcfi_typeid = if let Some(instance) = instance { - kcfi_typeid_for_instance(self.tcx, instance, options) + kcfi::typeid_for_instance(self.tcx, instance, options) } else { - kcfi_typeid_for_fnabi(self.tcx, fn_abi, options) + kcfi::typeid_for_fnabi(self.tcx, fn_abi, options) }; Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)])) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index df9f066e58a..d32baa6dc02 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -180,13 +180,13 @@ pub unsafe fn create_module<'ll>( // to ensure intrinsic calls don't use it. if !sess.needs_plt() { let avoid_plt = c"RtLibUseGOT".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1); } // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.) if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() { let canonical_jump_tables = c"CFI Canonical Jump Tables".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, canonical_jump_tables, @@ -197,7 +197,7 @@ pub unsafe fn create_module<'ll>( // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.) if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() { let enable_split_lto_unit = c"EnableSplitLTOUnit".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, enable_split_lto_unit, @@ -208,7 +208,7 @@ pub unsafe fn create_module<'ll>( // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.) if sess.is_sanitizer_kcfi_enabled() { let kcfi = c"kcfi".as_ptr().cast(); - llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); + llvm::LLVMRustAddModuleFlagU32(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1); } // Control Flow Guard is currently only supported by the MSVC linker on Windows. @@ -217,7 +217,7 @@ pub unsafe fn create_module<'ll>( CFGuard::Disabled => {} CFGuard::NoChecks => { // Set `cfguard=1` module flag to emit metadata only. - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Warning, c"cfguard".as_ptr() as *const _, @@ -226,7 +226,7 @@ pub unsafe fn create_module<'ll>( } CFGuard::Checks => { // Set `cfguard=2` module flag to emit metadata and checks. - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Warning, c"cfguard".as_ptr() as *const _, @@ -238,26 +238,26 @@ pub unsafe fn create_module<'ll>( if let Some(BranchProtection { bti, pac_ret }) = sess.opts.unstable_opts.branch_protection { if sess.target.arch == "aarch64" { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"branch-target-enforcement".as_ptr().cast(), bti.into(), ); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"sign-return-address".as_ptr().cast(), pac_ret.is_some().into(), ); let pac_opts = pac_ret.unwrap_or(PacRet { leaf: false, key: PAuthKey::A }); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"sign-return-address-all".as_ptr().cast(), pac_opts.leaf.into(), ); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Min, c"sign-return-address-with-bkey".as_ptr().cast(), @@ -273,7 +273,7 @@ pub unsafe fn create_module<'ll>( // Pass on the control-flow protection flags to LLVM (equivalent to `-fcf-protection` in Clang). if let CFProtection::Branch | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, c"cf-protection-branch".as_ptr().cast(), @@ -281,7 +281,7 @@ pub unsafe fn create_module<'ll>( ) } if let CFProtection::Return | CFProtection::Full = sess.opts.unstable_opts.cf_protection { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Override, c"cf-protection-return".as_ptr().cast(), @@ -290,7 +290,7 @@ pub unsafe fn create_module<'ll>( } if sess.opts.unstable_opts.virtual_function_elimination { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Error, c"Virtual Function Elim".as_ptr().cast(), @@ -300,7 +300,7 @@ pub unsafe fn create_module<'ll>( // Set module flag to enable Windows EHCont Guard (/guard:ehcont). if sess.opts.unstable_opts.ehcont_guard { - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( llmod, llvm::LLVMModFlagBehavior::Warning, c"ehcontguard".as_ptr() as *const _, @@ -326,6 +326,22 @@ pub unsafe fn create_module<'ll>( llvm::LLVMMDNodeInContext(llcx, &name_metadata, 1), ); + // Emit RISC-V specific target-abi metadata + // to workaround lld as the LTO plugin not + // correctly setting target-abi for the LTO object + // FIXME: https://github.com/llvm/llvm-project/issues/50591 + // If llvm_abiname is empty, emit nothing. + let llvm_abiname = &sess.target.options.llvm_abiname; + if matches!(sess.target.arch.as_ref(), "riscv32" | "riscv64") && !llvm_abiname.is_empty() { + llvm::LLVMRustAddModuleFlagString( + llmod, + llvm::LLVMModFlagBehavior::Error, + c"target-abi".as_ptr(), + llvm_abiname.as_ptr().cast(), + llvm_abiname.len(), + ); + } + // Add module flags specified via -Z llvm_module_flag for (key, value, behavior) in &sess.opts.unstable_opts.llvm_module_flag { let key = format!("{key}\0"); @@ -341,7 +357,7 @@ pub unsafe fn create_module<'ll>( // We already checked this during option parsing _ => unreachable!(), }; - llvm::LLVMRustAddModuleFlag(llmod, behavior, key.as_ptr().cast(), *value) + llvm::LLVMRustAddModuleFlagU32(llmod, behavior, key.as_ptr().cast(), *value) } llmod diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index d3a851b40c0..4fdaa59e0e5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -110,7 +110,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { .unstable_opts .dwarf_version .unwrap_or(sess.target.default_dwarf_version); - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, c"Dwarf Version".as_ptr().cast(), @@ -118,7 +118,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { ); } else { // Indicate that we want CodeView debug information on MSVC - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, c"CodeView".as_ptr().cast(), @@ -127,7 +127,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { } // Prevent bitcode readers from deleting the debug info. - llvm::LLVMRustAddModuleFlag( + llvm::LLVMRustAddModuleFlagU32( self.llmod, llvm::LLVMModFlagBehavior::Warning, c"Debug Info Version".as_ptr().cast(), diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index f86cdcaa6f7..7117c4a0ed9 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -22,10 +22,7 @@ use itertools::Itertools; use rustc_codegen_ssa::traits::TypeMembershipMethods; use rustc_data_structures::fx::FxIndexSet; use rustc_middle::ty::{Instance, Ty}; -use rustc_symbol_mangling::typeid::{ - kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance, - TypeIdOptions, -}; +use rustc_sanitizers::{cfi, kcfi}; use smallvec::SmallVec; /// Declare a function. @@ -145,27 +142,29 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { if let Some(instance) = instance { let mut typeids = FxIndexSet::default(); for options in [ - TypeIdOptions::GENERALIZE_POINTERS, - TypeIdOptions::NORMALIZE_INTEGERS, - TypeIdOptions::USE_CONCRETE_SELF, + cfi::TypeIdOptions::GENERALIZE_POINTERS, + cfi::TypeIdOptions::NORMALIZE_INTEGERS, + cfi::TypeIdOptions::USE_CONCRETE_SELF, ] .into_iter() .powerset() - .map(TypeIdOptions::from_iter) + .map(cfi::TypeIdOptions::from_iter) { - let typeid = typeid_for_instance(self.tcx, instance, options); + let typeid = cfi::typeid_for_instance(self.tcx, instance, options); if typeids.insert(typeid.clone()) { self.add_type_metadata(llfn, typeid); } } } else { - for options in - [TypeIdOptions::GENERALIZE_POINTERS, TypeIdOptions::NORMALIZE_INTEGERS] - .into_iter() - .powerset() - .map(TypeIdOptions::from_iter) + for options in [ + cfi::TypeIdOptions::GENERALIZE_POINTERS, + cfi::TypeIdOptions::NORMALIZE_INTEGERS, + ] + .into_iter() + .powerset() + .map(cfi::TypeIdOptions::from_iter) { - let typeid = typeid_for_fnabi(self.tcx, fn_abi, options); + let typeid = cfi::typeid_for_fnabi(self.tcx, fn_abi, options); self.add_type_metadata(llfn, typeid); } } @@ -173,19 +172,19 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { if self.tcx.sess.is_sanitizer_kcfi_enabled() { // LLVM KCFI does not support multiple !kcfi_type attachments - let mut options = TypeIdOptions::empty(); + let mut options = kcfi::TypeIdOptions::empty(); if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() { - options.insert(TypeIdOptions::GENERALIZE_POINTERS); + options.insert(kcfi::TypeIdOptions::GENERALIZE_POINTERS); } if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() { - options.insert(TypeIdOptions::NORMALIZE_INTEGERS); + options.insert(kcfi::TypeIdOptions::NORMALIZE_INTEGERS); } if let Some(instance) = instance { - let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, instance, options); + let kcfi_typeid = kcfi::typeid_for_instance(self.tcx, instance, options); self.set_kcfi_type_metadata(llfn, kcfi_typeid); } else { - let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options); + let kcfi_typeid = kcfi::typeid_for_fnabi(self.tcx, fn_abi, options); self.set_kcfi_type_metadata(llfn, kcfi_typeid); } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 284bc74d5c4..5509baaa3e9 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1801,12 +1801,21 @@ extern "C" { /// /// In order for Rust-C LTO to work, module flags must be compatible with Clang. What /// "compatible" means depends on the merge behaviors involved. - pub fn LLVMRustAddModuleFlag( + pub fn LLVMRustAddModuleFlagU32( M: &Module, merge_behavior: LLVMModFlagBehavior, name: *const c_char, value: u32, ); + + pub fn LLVMRustAddModuleFlagString( + M: &Module, + merge_behavior: LLVMModFlagBehavior, + name: *const c_char, + value: *const c_char, + value_len: size_t, + ); + pub fn LLVMRustHasModuleFlag(M: &Module, name: *const c_char, len: size_t) -> bool; pub fn LLVMRustDIBuilderCreate(M: &Module) -> &mut DIBuilder<'_>; diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index 22b58c13949..ef55682d541 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -231,7 +231,11 @@ impl<'a> ArArchiveBuilder<'a> { "gnu" => ArchiveKind::Gnu, "bsd" => ArchiveKind::Bsd, "darwin" => ArchiveKind::Darwin, - "coff" => ArchiveKind::Coff, + "coff" => { + // FIXME: ar_archive_writer doesn't support COFF archives yet. + // https://github.com/rust-lang/ar_archive_writer/issues/9 + ArchiveKind::Gnu + } "aix_big" => ArchiveKind::AixBig, kind => { self.sess.dcx().emit_fatal(UnknownArchiveKind { kind }); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index b7bcaac3b18..e7f692144ff 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -528,12 +528,20 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) { let mut files = Vec::new(); if let Some(object_file_path) = &module.object { - files.push(("o", object_file_path.as_path())); + files.push((OutputType::Object.extension(), object_file_path.as_path())); } if let Some(dwarf_object_file_path) = &module.dwarf_object { files.push(("dwo", dwarf_object_file_path.as_path())); } - + if let Some(path) = &module.assembly { + files.push((OutputType::Assembly.extension(), path.as_path())); + } + if let Some(path) = &module.llvm_ir { + files.push((OutputType::LlvmAssembly.extension(), path.as_path())); + } + if let Some(path) = &module.bytecode { + files.push((OutputType::Bitcode.extension(), path.as_path())); + } if let Some((id, product)) = copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, files.as_slice()) { @@ -937,12 +945,28 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>( load_from_incr_comp_dir(dwarf_obj_out, saved_dwarf_object_file) }); + let load_from_incr_cache = |perform, output_type: OutputType| { + if perform { + let saved_file = module.source.saved_files.get(output_type.extension())?; + let output_path = cgcx.output_filenames.temp_path(output_type, Some(&module.name)); + load_from_incr_comp_dir(output_path, &saved_file) + } else { + None + } + }; + + let assembly = load_from_incr_cache(module_config.emit_asm, OutputType::Assembly); + let llvm_ir = load_from_incr_cache(module_config.emit_ir, OutputType::LlvmAssembly); + let bytecode = load_from_incr_cache(module_config.emit_bc, OutputType::Bitcode); + WorkItemResult::Finished(CompiledModule { name: module.name, kind: ModuleKind::Regular, object, dwarf_object, - bytecode: None, + bytecode, + assembly, + llvm_ir, }) } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 410b5d27c57..c4c16ee7311 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -656,6 +656,8 @@ pub fn codegen_crate<B: ExtraBackendMethods>( object: Some(file_name), dwarf_object: None, bytecode: None, + assembly: None, + llvm_ir: None, } }) }); diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 64448441acb..5f0dcf9510f 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -202,6 +202,16 @@ fn push_debuginfo_type_name<'tcx>( } } } + ty::Pat(inner_type, pat) => { + if cpp_like_debuginfo { + output.push_str("pat$<"); + push_debuginfo_type_name(tcx, inner_type, true, output, visited); + // FIXME(wg-debugging): implement CPP like printing for patterns. + write!(output, ",{:?}>", pat).unwrap(); + } else { + write!(output, "{:?}", t).unwrap(); + } + } ty::Slice(inner_type) => { if cpp_like_debuginfo { output.push_str("slice2$<"); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 9be8dcf166d..80fe7e0bb78 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -79,13 +79,26 @@ impl<M> ModuleCodegen<M> { emit_obj: bool, emit_dwarf_obj: bool, emit_bc: bool, + emit_asm: bool, + emit_ir: bool, outputs: &OutputFilenames, ) -> CompiledModule { let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name))); let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); + let assembly = emit_asm.then(|| outputs.temp_path(OutputType::Assembly, Some(&self.name))); + let llvm_ir = + emit_ir.then(|| outputs.temp_path(OutputType::LlvmAssembly, Some(&self.name))); - CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode } + CompiledModule { + name: self.name.clone(), + kind: self.kind, + object, + dwarf_object, + bytecode, + assembly, + llvm_ir, + } } } @@ -96,6 +109,8 @@ pub struct CompiledModule { pub object: Option<PathBuf>, pub dwarf_object: Option<PathBuf>, pub bytecode: Option<PathBuf>, + pub assembly: Option<PathBuf>, // --emit=asm + pub llvm_ir: Option<PathBuf>, // --emit=llvm-ir, llvm-bc is in bytecode } pub struct CachedModuleCodegen { diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 387a5366b20..1f4473d2ec4 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -257,20 +257,19 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // Apply debuginfo to the newly allocated locals. fx.debug_introduce_locals(&mut start_bx); - let reachable_blocks = mir.reachable_blocks_in_mono(cx.tcx(), instance); - // The builders will be created separately for each basic block at `codegen_block`. // So drop the builder of `start_llbb` to avoid having two at the same time. drop(start_bx); + let reachable_blocks = traversal::mono_reachable_as_bitset(mir, cx.tcx(), instance); + // Codegen the body of each block using reverse postorder for (bb, _) in traversal::reverse_postorder(mir) { if reachable_blocks.contains(bb) { fx.codegen_block(bb); } else { - // This may have references to things we didn't monomorphize, so we - // don't actually codegen the body. We still create the block so - // terminators in other blocks can reference it without worry. + // We want to skip this block, because it's not reachable. But we still create + // the block so terminators in other blocks can reference it. fx.codegen_block_as_unreachable(bb); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4d746c89f1f..d62f560f11f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -682,7 +682,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.cx().const_usize(val) } mir::NullOp::UbChecks => { - let val = bx.tcx().sess.opts.debug_assertions; + let val = bx.tcx().sess.ub_checks(); bx.cx().const_bool(val) } }; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index d91ad3fcab1..dcfce4e35e0 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::mir; use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId}; use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout}; @@ -98,6 +99,16 @@ fn const_to_valtree_inner<'tcx>( Ok(ty::ValTree::Leaf(val.assert_int())) } + ty::Pat(base, ..) => { + let mut place = place.clone(); + // The valtree of the base type is the same as the valtree of the pattern type. + // Since the returned valtree does not contain the type or layout, we can just + // switch to the base type. + place.layout = ecx.layout_of(*base).unwrap(); + ensure_sufficient_stack(|| const_to_valtree_inner(ecx, &place, num_nodes)) + }, + + ty::RawPtr(_, _) => { // Not all raw pointers are allowed, as we cannot properly test them for // equality at compile-time (see `ptr_guaranteed_cmp`). @@ -273,7 +284,7 @@ pub fn valtree_to_const_value<'tcx>( let (param_env, ty) = param_env_ty.into_parts(); - match ty.kind() { + match *ty.kind() { ty::FnDef(..) => { assert!(valtree.unwrap_branch().is_empty()); mir::ConstValue::ZeroSized @@ -286,10 +297,11 @@ pub fn valtree_to_const_value<'tcx>( ), } } + ty::Pat(ty, _) => valtree_to_const_value(tcx, param_env.and(ty), valtree), ty::Ref(_, inner_ty, _) => { let mut ecx = mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, param_env, CanAccessMutGlobal::No); - let imm = valtree_to_ref(&mut ecx, valtree, *inner_ty); + let imm = valtree_to_ref(&mut ecx, valtree, inner_ty); let imm = ImmTy::from_immediate(imm, tcx.layout_of(param_env_ty).unwrap()); op_to_const(&ecx, &imm.into(), /* for diagnostics */ false) } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 3283bcc4c45..62d169db628 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -1060,6 +1060,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ty::Tuple(tys) => tys.last().iter().all(|ty| is_very_trivially_sized(**ty)), + ty::Pat(ty, ..) => is_very_trivially_sized(*ty), + // We don't want to do any queries, so there is not much we can do with ADTs. ty::Adt(..) => false, diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index a8478f721c7..63c709d8aed 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -69,6 +69,10 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>( ty::Alias(..) | ty::Param(_) | ty::Placeholder(_) | ty::Infer(_) => { throw_inval!(TooGeneric) } + ty::Pat(_, pat) => match **pat { + ty::PatternKind::Range { .. } => ConstValue::from_target_usize(0u64, &tcx), + // Future pattern kinds may have more variants + }, ty::Bound(_, _) => bug!("bound ty during ctfe"), ty::Bool | ty::Char diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 9114ffff6fd..db6c2833b9d 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -258,7 +258,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = layout.offset_of_subfield(self, fields.iter()).bytes(); Scalar::from_target_usize(val, self) } - mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.opts.debug_assertions), + mir::NullOp::UbChecks => Scalar::from_bool(self.tcx.sess.ub_checks()), }; self.write_scalar(val, &dest)?; } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d18600ce7d7..9911c59d4b8 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -640,6 +640,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' | ty::Str | ty::Dynamic(..) | ty::Closure(..) + | ty::Pat(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) => Ok(false), // Some types only occur during typechecking, they have no layout. diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs index f3db7d4cd42..e474b952938 100644 --- a/compiler/rustc_const_eval/src/util/type_name.rs +++ b/compiler/rustc_const_eval/src/util/type_name.rs @@ -31,6 +31,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { | ty::Uint(_) | ty::Float(_) | ty::Str + | ty::Pat(_, _) | ty::Array(_, _) | ty::Slice(_) | ty::RawPtr(_, _) diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl index 1b69a6e2fbe..5b39248302e 100644 --- a/compiler/rustc_driver_impl/messages.ftl +++ b/compiler/rustc_driver_impl/messages.ftl @@ -1,10 +1,7 @@ driver_impl_ice = the compiler unexpectedly panicked. this is a bug. driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url} driver_impl_ice_bug_report_internal_feature = using internal features is not supported and expected to cause internal compiler errors when used incorrectly -driver_impl_ice_bug_report_outdated = - it seems that this compiler `{$version}` is outdated, a newer nightly should have been released in the mean time - .update = please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists - .url = if the problem still persists, we would appreciate a bug report: {$bug_report_url} +driver_impl_ice_bug_report_update_note = please make sure that you have updated to the latest nightly driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden driver_impl_ice_flags = compiler flags: {$flags} diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index b4007aeb8d7..1f44621736c 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -61,7 +61,7 @@ use std::str; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, OnceLock}; use std::time::{Instant, SystemTime}; -use time::{Date, OffsetDateTime, Time}; +use time::OffsetDateTime; #[allow(unused_macros)] macro do_not_use_print($($t:tt)*) { @@ -1385,9 +1385,6 @@ pub fn install_ice_hook( using_internal_features } -const DATE_FORMAT: &[time::format_description::FormatItem<'static>] = - &time::macros::format_description!("[year]-[month]-[day]"); - /// Prints the ICE message, including query stack, but without backtrace. /// /// The message will point the user at `bug_report_url` to report the ICE. @@ -1416,33 +1413,14 @@ fn report_ice( dcx.emit_err(session_diagnostics::Ice); } - use time::ext::NumericalDuration; - - // Try to hint user to update nightly if applicable when reporting an ICE. - // Attempt to calculate when current version was released, and add 12 hours - // as buffer. If the current version's release timestamp is older than - // the system's current time + 24 hours + 12 hours buffer if we're on - // nightly. - if let Some("nightly") = option_env!("CFG_RELEASE_CHANNEL") - && let Some(version) = option_env!("CFG_VERSION") - && let Some(ver_date_str) = option_env!("CFG_VER_DATE") - && let Ok(ver_date) = Date::parse(&ver_date_str, DATE_FORMAT) - && let ver_datetime = OffsetDateTime::new_utc(ver_date, Time::MIDNIGHT) - && let system_datetime = OffsetDateTime::from(SystemTime::now()) - && system_datetime.checked_sub(36.hours()).is_some_and(|d| d > ver_datetime) - && !using_internal_features.load(std::sync::atomic::Ordering::Relaxed) - { - dcx.emit_note(session_diagnostics::IceBugReportOutdated { - version, - bug_report_url, - note_update: (), - note_url: (), - }); + if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { + dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); } else { - if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) { - dcx.emit_note(session_diagnostics::IceBugReportInternalFeature); - } else { - dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url }); + + // Only emit update nightly hint for users on nightly builds. + if rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() { + dcx.emit_note(session_diagnostics::UpdateNightlyNote); } } diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index c9bbe45b212..c0c6201f73d 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -336,7 +336,8 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirTree => { let tcx = ex.tcx(); let mut out = String::new(); - if rustc_hir_analysis::check_crate(tcx).is_err() { + rustc_hir_analysis::check_crate(tcx); + if tcx.dcx().has_errors().is_some() { FatalError.raise(); } debug!("pretty printing THIR tree"); @@ -348,7 +349,8 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { ThirFlat => { let tcx = ex.tcx(); let mut out = String::new(); - if rustc_hir_analysis::check_crate(tcx).is_err() { + rustc_hir_analysis::check_crate(tcx); + if tcx.dcx().has_errors().is_some() { FatalError.raise(); } debug!("pretty printing THIR flat"); diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index 62d0da62d2a..1a9683e840a 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -43,19 +43,12 @@ pub(crate) struct IceBugReport<'a> { } #[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report_internal_feature)] -pub(crate) struct IceBugReportInternalFeature; +#[diag(driver_impl_ice_bug_report_update_note)] +pub(crate) struct UpdateNightlyNote; #[derive(Diagnostic)] -#[diag(driver_impl_ice_bug_report_outdated)] -pub(crate) struct IceBugReportOutdated<'a> { - pub version: &'a str, - pub bug_report_url: &'a str, - #[note(driver_impl_update)] - pub note_update: (), - #[note(driver_impl_url)] - pub note_url: (), -} +#[diag(driver_impl_ice_bug_report_internal_feature)] +pub(crate) struct IceBugReportInternalFeature; #[derive(Diagnostic)] #[diag(driver_impl_ice_version)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0699.md b/compiler/rustc_error_codes/src/error_codes/E0699.md index 454d2507e5e..1094ebf4b8f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0699.md +++ b/compiler/rustc_error_codes/src/error_codes/E0699.md @@ -1,8 +1,10 @@ +#### Note: this error code is no longer emitted by the compiler. + A method was called on a raw pointer whose inner type wasn't completely known. Erroneous code example: -```compile_fail,edition2018,E0699 +```compile_fail,edition2018 # #![deny(warnings)] # fn main() { let foo = &1; diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index da688e385aa..f4a33a05c1b 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -441,7 +441,7 @@ E0695: 0695, E0696: 0696, E0697: 0697, E0698: 0698, -E0699: 0699, +E0699: 0699, // REMOVED: merged into generic inference var error E0700: 0700, E0701: 0701, E0703: 0703, diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs index f90190797ae..6c0551848d6 100644 --- a/compiler/rustc_errors/src/diagnostic_impls.rs +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -46,6 +46,7 @@ impl<'a, T: Clone + IntoDiagArg> IntoDiagArg for &'a T { } } +#[macro_export] macro_rules! into_diag_arg_using_display { ($( $ty:ty ),+ $(,)?) => { $( diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index a83f9f56beb..1eee11604ce 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -355,6 +355,8 @@ declare_features! ( (accepted, type_alias_enum_variants, "1.37.0", Some(49683)), /// Allows macros to appear in the type position. (accepted, type_macros, "1.13.0", Some(27245)), + /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`). + (accepted, type_privacy_lints, "CURRENT_RUSTC_VERSION", Some(48054)), /// Allows `const _: TYPE = VALUE`. (accepted, underscore_const_names, "1.37.0", Some(54912)), /// Allows `use path as _;` and `extern crate c as _;`. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 6a8a1722bcb..db94e0b08bc 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -25,6 +25,7 @@ pub type GatedCfg = (Symbol, Symbol, GateFn); const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)), + (sym::ub_checks, sym::cfg_ub_checks, cfg_fn!(cfg_ub_checks)), (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), ( sym::target_has_atomic_equal_alignment, diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 36db377f7e0..e6b19817de3 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -215,6 +215,8 @@ declare_features! ( (internal, omit_gdb_pretty_printer_section, "1.5.0", None), /// Set the maximum pattern complexity allowed (not limited by default). (internal, pattern_complexity, "1.78.0", None), + /// Allows using pattern types. + (internal, pattern_types, "CURRENT_RUSTC_VERSION", Some(123646)), /// Allows using `#[prelude_import]` on glob `use` items. (internal, prelude_import, "1.2.0", None), /// Used to identify crates that contain the profiler runtime. @@ -381,6 +383,8 @@ declare_features! ( (unstable, cfg_target_has_atomic_equal_alignment, "1.60.0", Some(93822)), /// Allows `cfg(target_thread_local)`. (unstable, cfg_target_thread_local, "1.7.0", Some(29594)), + /// Allows the use of `#[cfg(ub_checks)` to check if UB checks are enabled. + (unstable, cfg_ub_checks, "CURRENT_RUSTC_VERSION", Some(123499)), /// Allow conditional compilation depending on rust version (unstable, cfg_version, "1.45.0", Some(64796)), /// Allows to use the `#[cfi_encoding = ""]` attribute. @@ -613,8 +617,6 @@ declare_features! ( /// Allows creation of instances of a struct by moving fields that have /// not changed from prior instances of the same struct (RFC #2528) (unstable, type_changing_struct_update, "1.58.0", Some(86555)), - /// Allows using type privacy lints (`private_interfaces`, `private_bounds`, `unnameable_types`). - (unstable, type_privacy_lints, "1.72.0", Some(48054)), /// Enables rustc to generate code that instructs libstd to NOT ignore SIGPIPE. (unstable, unix_sigpipe, "1.65.0", Some(97889)), /// Allows unnamed fields of struct and union type diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index e8cecb1930f..2662f5661ba 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -113,6 +113,9 @@ pub enum DefKind { InlineConst, /// Opaque type, aka `impl Trait`. OpaqueTy, + /// A field in a struct, enum or union. e.g. + /// - `bar` in `struct Foo { bar: u8 }` + /// - `Foo::Bar::0` in `enum Foo { Bar(u8) }` Field, /// Lifetime parameter: the `'a` in `struct Foo<'a> { ... }` LifetimeParam, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index f21cd653f96..c6e3ad31f01 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2624,6 +2624,8 @@ pub enum TyKind<'hir> { Infer, /// Placeholder for a type that has failed to be defined. Err(rustc_span::ErrorGuaranteed), + /// Pattern types (`pattern_type!(u32 is 1..)`) + Pat(&'hir Ty<'hir>, &'hir Pat<'hir>), } #[derive(Debug, Clone, Copy, HashStable_Generic)] diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 8c44f21a57b..5da9d4444da 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -356,6 +356,11 @@ pub trait Visitor<'v>: Sized { fn visit_ty(&mut self, t: &'v Ty<'v>) -> Self::Result { walk_ty(self, t) } + fn visit_pattern_type_pattern(&mut self, _p: &'v Pat<'v>) { + // Do nothing. Only a few visitors need to know the details of the pattern type, + // and they opt into it. All other visitors will just choke on our fake patterns + // because they aren't in a body. + } fn visit_generic_param(&mut self, p: &'v GenericParam<'v>) -> Self::Result { walk_generic_param(self, p) } @@ -882,6 +887,10 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) -> V::Resul TyKind::AnonAdt(item_id) => { try_visit!(visitor.visit_nested_item(item_id)); } + TyKind::Pat(ty, pat) => { + try_visit!(visitor.visit_ty(ty)); + try_visit!(visitor.visit_pattern_type_pattern(pat)); + } } V::Result::output() } diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d8a90d62dac..86b8b6d6b2b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -349,9 +349,15 @@ hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function .suggestion = cast the value to `{$cast_ty}` .help = cast the value to `{$cast_ty}` +hir_analysis_pattern_type_non_const_range = "range patterns must have constant range start and end" +hir_analysis_pattern_type_wild_pat = "wildcard patterns are not permitted for pattern types" + .label = "this type is the same as the inner type without a pattern" hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind} .label = not allowed in type signatures +hir_analysis_redundant_lifetime_args = unnecessary lifetime parameter `{$victim}` + .note = you can use the `{$candidate}` lifetime directly, in place of `{$victim}` + hir_analysis_requires_note = the `{$trait_name}` impl for `{$ty}` requires that `{$error_predicate}` hir_analysis_return_type_notation_equality_bound = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 739a7086992..8d4ae10d4bf 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt}; use rustc_infer::traits::{Obligation, TraitEngineExt as _}; use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS; use rustc_middle::middle::stability::EvalResult; -use rustc_middle::traits::{DefiningAnchor, ObligationCauseCode}; +use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES}; use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt}; @@ -345,10 +345,7 @@ fn check_opaque_meets_bounds<'tcx>( }; let param_env = tcx.param_env(defining_use_anchor); - let infcx = tcx - .infer_ctxt() - .with_opaque_type_inference(DefiningAnchor::bind(tcx, defining_use_anchor)) - .build(); + let infcx = tcx.infer_ctxt().with_opaque_type_inference(defining_use_anchor).build(); let ocx = ObligationCtxt::new(&infcx); let args = match *origin { @@ -1567,7 +1564,7 @@ pub(super) fn check_coroutine_obligations( .ignoring_regions() // Bind opaque types to type checking root, as they should have been checked by borrowck, // but may show up in some cases, like when (root) obligations are stalled in the new solver. - .with_opaque_type_inference(DefiningAnchor::bind(tcx, typeck.hir_owner.def_id)) + .with_opaque_type_inference(typeck.hir_owner.def_id) .build(); let mut fulfillment_cx = <dyn TraitEngine<'_>>::new(&infcx); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 4fd7c870fc7..c26f982fa47 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -8,11 +8,13 @@ use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::lang_items::LangItem; use rustc_hir::ItemKind; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; +use rustc_macros::LintDiagnostic; use rustc_middle::query::Providers; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::trait_def::TraitSpecializationKind; @@ -136,6 +138,8 @@ where infcx.implied_bounds_tys_compat(param_env, body_def_id, &assumed_wf_types, false); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); + lint_redundant_lifetimes(tcx, body_def_id, &outlives_env); + let errors = infcx.resolve_regions(&outlives_env); if errors.is_empty() { return Ok(()); @@ -2010,6 +2014,137 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error res } +fn lint_redundant_lifetimes<'tcx>( + tcx: TyCtxt<'tcx>, + owner_id: LocalDefId, + outlives_env: &OutlivesEnvironment<'tcx>, +) { + let def_kind = tcx.def_kind(owner_id); + match def_kind { + DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Trait + | DefKind::TraitAlias + | DefKind::Fn + | DefKind::Const + | DefKind::Impl { of_trait: _ } => { + // Proceed + } + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + let parent_def_id = tcx.local_parent(owner_id); + if matches!(tcx.def_kind(parent_def_id), DefKind::Impl { of_trait: true }) { + // Don't check for redundant lifetimes for associated items of trait + // implementations, since the signature is required to be compatible + // with the trait, even if the implementation implies some lifetimes + // are redundant. + return; + } + } + DefKind::Mod + | DefKind::Variant + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TyParam + | DefKind::ConstParam + | DefKind::Static { .. } + | DefKind::Ctor(_, _) + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Closure => return, + } + + // The ordering of this lifetime map is a bit subtle. + // + // Specifically, we want to find a "candidate" lifetime that precedes a "victim" lifetime, + // where we can prove that `'candidate = 'victim`. + // + // `'static` must come first in this list because we can never replace `'static` with + // something else, but if we find some lifetime `'a` where `'a = 'static`, we want to + // suggest replacing `'a` with `'static`. + let mut lifetimes = vec![tcx.lifetimes.re_static]; + lifetimes.extend( + ty::GenericArgs::identity_for_item(tcx, owner_id).iter().filter_map(|arg| arg.as_region()), + ); + // If we are in a function, add its late-bound lifetimes too. + if matches!(def_kind, DefKind::Fn | DefKind::AssocFn) { + for var in tcx.fn_sig(owner_id).instantiate_identity().bound_vars() { + let ty::BoundVariableKind::Region(kind) = var else { continue }; + lifetimes.push(ty::Region::new_late_param(tcx, owner_id.to_def_id(), kind)); + } + } + lifetimes.retain(|candidate| candidate.has_name()); + + // Keep track of lifetimes which have already been replaced with other lifetimes. + // This makes sure that if `'a = 'b = 'c`, we don't say `'c` should be replaced by + // both `'a` and `'b`. + let mut shadowed = FxHashSet::default(); + + for (idx, &candidate) in lifetimes.iter().enumerate() { + // Don't suggest removing a lifetime twice. We only need to check this + // here and not up in the `victim` loop because equality is transitive, + // so if A = C and B = C, then A must = B, so it'll be shadowed too in + // A's victim loop. + if shadowed.contains(&candidate) { + continue; + } + + for &victim in &lifetimes[(idx + 1)..] { + // We should only have late-bound lifetimes of the `BrNamed` variety, + // since we get these signatures straight from `hir_lowering`. And any + // other regions (ReError/ReStatic/etc.) shouldn't matter, since we + // can't really suggest to remove them. + let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. }) + | ty::ReLateParam(ty::LateParamRegion { + bound_region: ty::BoundRegionKind::BrNamed(def_id, _), + .. + })) = victim.kind() + else { + continue; + }; + + // Do not rename lifetimes not local to this item since they'll overlap + // with the lint running on the parent. We still want to consider parent + // lifetimes which make child lifetimes redundant, otherwise we would + // have truncated the `identity_for_item` args above. + if tcx.parent(def_id) != owner_id.to_def_id() { + continue; + } + + // If `candidate <: victim` and `victim <: candidate`, then they're equal. + if outlives_env.free_region_map().sub_free_regions(tcx, candidate, victim) + && outlives_env.free_region_map().sub_free_regions(tcx, victim, candidate) + { + shadowed.insert(victim); + tcx.emit_node_span_lint( + rustc_lint_defs::builtin::REDUNDANT_LIFETIMES, + tcx.local_def_id_to_hir_id(def_id.expect_local()), + tcx.def_span(def_id), + RedundantLifetimeArgsLint { candidate, victim }, + ); + } + } + } +} + +#[derive(LintDiagnostic)] +#[diag(hir_analysis_redundant_lifetime_args)] +#[note] +struct RedundantLifetimeArgsLint<'tcx> { + /// The lifetime we have found to be redundant. + victim: ty::Region<'tcx>, + // The lifetime we can replace the victim with. + candidate: ty::Region<'tcx>, +} + pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_type_wf, check_well_formed, ..*providers }; } diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs index 067878091a7..4a85e9983f4 100644 --- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs +++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs @@ -144,7 +144,12 @@ impl<'tcx> InherentCollect<'tcx> { let id = id.owner_id.def_id; let item_span = self.tcx.def_span(id); let self_ty = self.tcx.type_of(id).instantiate_identity(); - let self_ty = self.tcx.peel_off_weak_alias_tys(self_ty); + let mut self_ty = self.tcx.peel_off_weak_alias_tys(self_ty); + // We allow impls on pattern types exactly when we allow impls on the base type. + // FIXME(pattern_types): Figure out the exact coherence rules we want here. + while let ty::Pat(base, _) = *self_ty.kind() { + self_ty = base; + } match *self_ty.kind() { ty::Adt(def, _) => self.check_def_id(id, self_ty, def.did()), ty::Foreign(did) => self.check_def_id(id, self_ty, did), @@ -154,6 +159,7 @@ impl<'tcx> InherentCollect<'tcx> { ty::Dynamic(..) => { Err(self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span })) } + ty::Pat(_, _) => unreachable!(), ty::Bool | ty::Char | ty::Int(_) diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 1770f7b4e91..5585d2e069c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -206,6 +206,11 @@ pub(crate) fn orphan_check_impl( (LocalImpl::Disallow { problematic_kind }, NonlocalImpl::DisallowOther) } + ty::Pat(..) => ( + LocalImpl::Disallow { problematic_kind: "pattern type" }, + NonlocalImpl::DisallowOther, + ), + ty::Bool | ty::Char | ty::Int(..) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index f1b14adcb7a..c2205815ba6 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -165,10 +165,7 @@ pub(super) fn explicit_item_bounds_with_filter( ty::EarlyBinder::bind(bounds) } -pub(super) fn item_bounds( - tcx: TyCtxt<'_>, - def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { +pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> { tcx.explicit_item_bounds(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound))) }) @@ -177,7 +174,7 @@ pub(super) fn item_bounds( pub(super) fn item_super_predicates( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { +) -> ty::EarlyBinder<ty::Clauses<'_>> { tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| { tcx.mk_clauses_from_iter( util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(), @@ -188,12 +185,12 @@ pub(super) fn item_super_predicates( pub(super) fn item_non_self_assumptions( tcx: TyCtxt<'_>, def_id: DefId, -) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> { +) -> ty::EarlyBinder<ty::Clauses<'_>> { let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect(); let own_bounds: FxIndexSet<_> = tcx.item_super_predicates(def_id).skip_binder().iter().collect(); if all_bounds.len() == own_bounds.len() { - ty::EarlyBinder::bind(ty::List::empty()) + ty::EarlyBinder::bind(ty::ListWithCachedTypeInfo::empty()) } else { ty::EarlyBinder::bind(tcx.mk_clauses_from_iter(all_bounds.difference(&own_bounds).copied())) } diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 0b8ac9926e4..affd678fc6c 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -20,7 +20,6 @@ use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; -use rustc_session::lint; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -867,31 +866,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }) => { self.visit_lifetime(lifetime); walk_list!(self, visit_param_bound, bounds); - - if lifetime.res != hir::LifetimeName::Static { - for bound in bounds { - let hir::GenericBound::Outlives(lt) = bound else { - continue; - }; - if lt.res != hir::LifetimeName::Static { - continue; - } - self.insert_lifetime(lt, ResolvedArg::StaticLifetime); - self.tcx.node_span_lint( - lint::builtin::UNUSED_LIFETIMES, - lifetime.hir_id, - lifetime.ident.span, - format!("unnecessary lifetime parameter `{}`", lifetime.ident), - |lint| { - let help = format!( - "you can use the `'static` lifetime directly, in place of `{}`", - lifetime.ident, - ); - lint.help(help); - }, - ); - } - } } &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { lhs_ty, rhs_ty, .. }) => { self.visit_ty(lhs_ty); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2d4742fa1dc..d129614e0e1 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -7,6 +7,8 @@ use rustc_errors::{ use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::Ty; use rustc_span::{symbol::Ident, Span, Symbol}; +mod pattern_types; +pub use pattern_types::*; #[derive(Diagnostic)] #[diag(hir_analysis_ambiguous_assoc_item)] @@ -1629,3 +1631,10 @@ pub struct OpaqueCapturesHigherRankedLifetime { pub decl_span: Span, pub bad_place: &'static str, } + +#[derive(Diagnostic)] +#[diag(hir_analysis_pattern_type_non_const_range)] +pub struct NonConstRange { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/errors/pattern_types.rs b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs new file mode 100644 index 00000000000..008d2698989 --- /dev/null +++ b/compiler/rustc_hir_analysis/src/errors/pattern_types.rs @@ -0,0 +1,9 @@ +use rustc_macros::Diagnostic; +use rustc_span::Span; + +#[derive(Diagnostic)] +#[diag(hir_analysis_pattern_type_wild_pat)] +pub struct WildPatTy { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f726f2a7b89..59f0fac5aa7 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -21,7 +21,7 @@ mod object_safety; use crate::bounds::Bounds; use crate::collect::HirPlaceholderCollector; -use crate::errors::AmbiguousLifetimeBound; +use crate::errors::{AmbiguousLifetimeBound, WildPatTy}; use crate::hir_ty_lowering::errors::{prohibit_assoc_item_binding, GenericsArgsErrExtend}; use crate::hir_ty_lowering::generics::{check_generic_arg_count, lower_generic_args}; use crate::middle::resolve_bound_vars as rbv; @@ -39,6 +39,7 @@ use rustc_hir::{GenericArg, GenericArgs}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::middle::stability::AllowUnstable; +use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; use rustc_middle::ty::{ self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt, TypeVisitableExt, @@ -2195,6 +2196,68 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // handled specially and will not descend into this routine. self.ty_infer(None, hir_ty.span) } + hir::TyKind::Pat(ty, pat) => { + let ty = self.lower_ty(ty); + let pat_ty = match pat.kind { + hir::PatKind::Wild => { + let err = tcx.dcx().emit_err(WildPatTy { span: pat.span }); + Ty::new_error(tcx, err) + } + hir::PatKind::Range(start, end, include_end) => { + let expr_to_const = |expr: &'tcx hir::Expr<'tcx>| -> ty::Const<'tcx> { + let (expr, neg) = match expr.kind { + hir::ExprKind::Unary(hir::UnOp::Neg, negated) => { + (negated, Some((expr.hir_id, expr.span))) + } + _ => (expr, None), + }; + let c = match &expr.kind { + hir::ExprKind::Lit(lit) => { + let lit_input = + LitToConstInput { lit: &lit.node, ty, neg: neg.is_some() }; + match tcx.lit_to_const(lit_input) { + Ok(c) => c, + Err(LitToConstError::Reported(err)) => { + ty::Const::new_error(tcx, err, ty) + } + Err(LitToConstError::TypeError) => todo!(), + } + } + _ => { + let err = tcx + .dcx() + .emit_err(crate::errors::NonConstRange { span: expr.span }); + ty::Const::new_error(tcx, err, ty) + } + }; + self.record_ty(expr.hir_id, c.ty(), expr.span); + if let Some((id, span)) = neg { + self.record_ty(id, c.ty(), span); + } + c + }; + + let start = start.map(expr_to_const); + let end = end.map(expr_to_const); + + let include_end = match include_end { + hir::RangeEnd::Included => true, + hir::RangeEnd::Excluded => false, + }; + + let pat = tcx.mk_pat(ty::PatternKind::Range { start, end, include_end }); + Ty::new_pat(tcx, ty, pat) + } + hir::PatKind::Err(e) => Ty::new_error(tcx, e), + _ => Ty::new_error_with_message( + tcx, + pat.span, + format!("unsupported pattern for pattern type: {pat:#?}"), + ), + }; + self.record_ty(pat.hir_id, ty, pat.span); + pat_ty + } hir::TyKind::Err(guar) => Ty::new_error(tcx, *guar), }; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index b7786ec219c..5a374fa5e04 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -97,7 +97,6 @@ mod outlives; pub mod structured_errors; mod variance; -use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_middle::middle; @@ -153,11 +152,11 @@ pub fn provide(providers: &mut Providers) { hir_wf_check::provide(providers); } -pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { +pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); if tcx.features().rustc_attrs { - tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx))?; + let _ = tcx.sess.time("outlives_testing", || outlives::test::test_inferred_outlives(tcx)); } tcx.sess.time("coherence_checking", || { @@ -174,11 +173,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { }); if tcx.features().rustc_attrs { - tcx.sess.time("variance_testing", || variance::test::test_variance(tcx))?; + let _ = tcx.sess.time("variance_testing", || variance::test::test_variance(tcx)); } if tcx.features().rustc_attrs { - collect::test_opaque_hidden_types(tcx)?; + let _ = collect::test_opaque_hidden_types(tcx); } // Make sure we evaluate all static and (non-associated) const items, even if unused. @@ -213,8 +212,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> { }); tcx.ensure().check_unused_traits(()); - - Ok(()) } /// Lower a [`hir::Ty`] to a [`Ty`]. diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs index 28c86d8019e..20e4110e137 100644 --- a/compiler/rustc_hir_analysis/src/variance/constraints.rs +++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs @@ -249,6 +249,20 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { self.add_constraints_from_ty(current, typ, variance); } + ty::Pat(typ, pat) => { + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + if let Some(start) = start { + self.add_constraints_from_const(current, start, variance); + } + if let Some(end) = end { + self.add_constraints_from_const(current, end, variance); + } + } + } + self.add_constraints_from_ty(current, typ, variance); + } + ty::Slice(typ) => { self.add_constraints_from_ty(current, typ, variance); } diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index bd528432e70..a590c648d20 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -330,6 +330,11 @@ impl<'a> State<'a> { self.word("_"); } hir::TyKind::AnonAdt(..) => self.word("/* anonymous adt */"), + hir::TyKind::Pat(ty, pat) => { + self.print_type(ty); + self.word(" is "); + self.print_pat(pat); + } } self.end() } diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index 1d51101c940..18d9d739dd6 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -93,9 +93,6 @@ hir_typeck_lossy_provenance_ptr2int = .suggestion = use `.addr()` to obtain the address of a pointer .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_provenance()` instead -hir_typeck_method_call_on_unknown_raw_pointee = - cannot call a method on a raw pointer with an unknown pointee type - hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}` hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index c948b6343b7..92f74281ab9 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -40,17 +40,19 @@ use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef}; use rustc_session::lint; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::sym; use rustc_span::Span; +use rustc_span::DUMMY_SP; use rustc_trait_selection::infer::InferCtxtExt; /// Reifies a cast check to be checked once we have full type information for /// a function context. #[derive(Debug)] -pub struct CastCheck<'tcx> { +pub(crate) struct CastCheck<'tcx> { /// The expression whose value is being casted expr: &'tcx hir::Expr<'tcx>, /// The source type for the cast expression @@ -60,8 +62,6 @@ pub struct CastCheck<'tcx> { cast_ty: Ty<'tcx>, cast_span: Span, span: Span, - /// whether the cast is made in a const context or not. - pub constness: hir::Constness, } /// The kind of pointer and associated metadata (thin, length or vtable) - we @@ -130,6 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | ty::CoroutineWitness(..) | ty::RawPtr(_, _) | ty::Ref(..) + | ty::Pat(..) | ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) @@ -194,18 +195,45 @@ fn make_invalid_casting_error<'a, 'tcx>( ) } +/// If a cast from `from_ty` to `to_ty` is valid, returns a `Some` containing the kind +/// of the cast. +/// +/// This is a helper used from clippy. +pub fn check_cast<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + e: &'tcx hir::Expr<'tcx>, + from_ty: Ty<'tcx>, + to_ty: Ty<'tcx>, +) -> Option<CastKind> { + let hir_id = e.hir_id; + let local_def_id = hir_id.owner.def_id; + + let root_ctxt = crate::TypeckRootCtxt::new(tcx, local_def_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, local_def_id); + + if let Ok(check) = CastCheck::new( + &fn_ctxt, e, from_ty, to_ty, + // We won't show any errors to the user, so the span is irrelevant here. + DUMMY_SP, DUMMY_SP, + ) { + check.do_check(&fn_ctxt).ok() + } else { + None + } +} + impl<'a, 'tcx> CastCheck<'tcx> { - pub fn new( + pub(crate) fn new( fcx: &FnCtxt<'a, 'tcx>, expr: &'tcx hir::Expr<'tcx>, expr_ty: Ty<'tcx>, cast_ty: Ty<'tcx>, cast_span: Span, span: Span, - constness: hir::Constness, ) -> Result<CastCheck<'tcx>, ErrorGuaranteed> { let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span); - let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness }; + let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span }; // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once @@ -644,7 +672,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { /// Checks a cast, and report an error if one exists. In some cases, this /// can return Ok and create type errors in the fcx rather than returning /// directly. coercion-cast is handled in check instead of here. - pub fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> { + fn do_check(&self, fcx: &FnCtxt<'a, 'tcx>) -> Result<CastKind, CastError> { use rustc_middle::ty::cast::CastTy::*; use rustc_middle::ty::cast::IntTy::*; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 44b19318d5d..51d01afc4eb 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1318,6 +1318,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } +/// Check whether `ty` can be coerced to `output_ty`. +/// Used from clippy. +pub fn can_coerce<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: LocalDefId, + ty: Ty<'tcx>, + output_ty: Ty<'tcx>, +) -> bool { + let root_ctxt = crate::typeck_root_ctxt::TypeckRootCtxt::new(tcx, body_id); + let fn_ctxt = FnCtxt::new(&root_ctxt, param_env, body_id); + fn_ctxt.can_coerce(ty, output_ty) +} + /// CoerceMany encapsulates the pattern you should use when you have /// many expressions that are all getting coerced to a common /// type. This arises, for example, when you have a match (the result diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index f9b2ec69730..d399730bf3d 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -77,13 +77,6 @@ pub struct StructExprNonExhaustive { } #[derive(Diagnostic)] -#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = E0699)] -pub struct MethodCallOnUnknownRawPointee { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(hir_typeck_functional_record_update_on_non_struct, code = E0436)] pub struct FunctionalRecordUpdateOnNonStruct { #[primary_span] diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d8f62f7a2b6..7a1a2c498aa 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -544,13 +544,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if tcx.fn_sig(did).skip_binder().abi() == RustIntrinsic && tcx.item_name(did) == sym::transmute { - let from = fn_sig.inputs().skip_binder()[0]; + let Some(from) = fn_sig.inputs().skip_binder().get(0) else { + let e = self.dcx().span_delayed_bug( + tcx.def_span(did), + "intrinsic fn `transmute` defined with no parameters", + ); + self.set_tainted_by_errors(e); + return Ty::new_error(tcx, e); + }; let to = fn_sig.output().skip_binder(); // We defer the transmute to the end of typeck, once all inference vars have // been resolved or we errored. This is important as we can only check transmute // on concrete types, but the output type may not be known yet (it would only // be known if explicitly specified via turbofish). - self.deferred_transmute_checks.borrow_mut().push((from, to, expr.hir_id)); + self.deferred_transmute_checks.borrow_mut().push((*from, to, expr.hir_id)); } if !tcx.features().unsized_fn_params { // We want to remove some Sized bounds from std functions, @@ -1383,15 +1390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // Defer other checks until we're done type checking. let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - match cast::CastCheck::new( - self, - e, - t_expr, - t_cast, - t.span, - expr.span, - hir::Constness::NotConst, - ) { + match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) { Ok(cast_check) => { debug!( "check_expr_cast: deferring cast from {:?} to {:?}: {:?}", @@ -2024,8 +2023,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .sess .source_map() - .span_extend_while(range_start.span, |c| c.is_whitespace()) - .unwrap_or(range_start.span) + .span_extend_while_whitespace(range_start.span) .shrink_to_hi() .to(range_end.span); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 85d04f7d1c4..f1e82543a99 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -730,8 +730,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { for ty in ret_ty.walk() { if let ty::GenericArgKind::Type(ty) = ty.unpack() && let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *ty.kind() - && let Some(def_id) = def_id.as_local() - && self.opaque_type_origin(def_id).is_some() + && self.can_define_opaque_ty(def_id) { return None; } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 05e7c5b2b41..0b69c7a2431 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -38,7 +38,7 @@ use std::ops::Deref; /// /// [`ItemCtxt`]: rustc_hir_analysis::collect::ItemCtxt /// [`InferCtxt`]: infer::InferCtxt -pub struct FnCtxt<'a, 'tcx> { +pub(crate) struct FnCtxt<'a, 'tcx> { pub(super) body_id: LocalDefId, /// The parameter environment used for proving trait obligations diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 80fd4be53e1..700dde184f2 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -42,8 +42,9 @@ mod typeck_root_ctxt; mod upvar; mod writeback; -pub use fn_ctxt::FnCtxt; -pub use typeck_root_ctxt::TypeckRootCtxt; +pub use coercion::can_coerce; +use fn_ctxt::FnCtxt; +use typeck_root_ctxt::TypeckRootCtxt; use crate::check::check_fn; use crate::coercion::DynamicCoerceMany; diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4e63600dbdf..28e17e1de36 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -3,7 +3,6 @@ use super::CandidateSource; use super::MethodError; use super::NoMatchData; -use crate::errors::MethodCallOnUnknownRawPointee; use crate::FnCtxt; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -430,21 +429,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if is_suggestion.0 { // Ambiguity was encountered during a suggestion. Just keep going. debug!("ProbeContext: encountered ambiguity in suggestion"); - } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types { + } else if bad_ty.reached_raw_pointer + && !self.tcx.features().arbitrary_self_types + && !self.tcx.sess.at_least_rust_2018() + { // this case used to be allowed by the compiler, // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) - if self.tcx.sess.at_least_rust_2018() { - self.dcx().emit_err(MethodCallOnUnknownRawPointee { span }); - } else { - self.tcx.node_span_lint( - lint::builtin::TYVAR_BEHIND_RAW_POINTER, - scope_expr_id, - span, - "type annotations needed", - |_| {}, - ); - } + self.tcx.node_span_lint( + lint::builtin::TYVAR_BEHIND_RAW_POINTER, + scope_expr_id, + span, + "type annotations needed", + |_| {}, + ); } else { // Ended up encountering a type variable when doing autoderef, // but it may not be a type variable after processing obligations @@ -455,10 +453,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); let ty = self.resolve_vars_if_possible(ty.value); let guar = match *ty.kind() { - ty::Infer(ty::TyVar(_)) => self - .err_ctxt() - .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true) - .emit(), + ty::Infer(ty::TyVar(_)) => { + let raw_ptr_call = + bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types; + let mut err = self.err_ctxt().emit_inference_failure_err( + self.body_id, + span, + ty.into(), + E0282, + !raw_ptr_call, + ); + if raw_ptr_call { + err.span_label(span, "cannot call a method on a raw pointer with an unknown pointee type"); + } + err.emit() + } ty::Error(guar) => guar, _ => bug!("unexpected bad final type in method autoderef"), }; diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs index e493e6a0a7e..694ddd0e3e8 100644 --- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs +++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs @@ -5,7 +5,6 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::HirIdMap; use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; -use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::def_id::LocalDefIdMap; @@ -27,7 +26,7 @@ use std::ops::Deref; /// `bar()` will each have their own `FnCtxt`, but they will /// share the inference context, will process obligations together, /// can access each other's local types (scoping permitted), etc. -pub struct TypeckRootCtxt<'tcx> { +pub(crate) struct TypeckRootCtxt<'tcx> { pub(super) infcx: InferCtxt<'tcx>, pub(super) typeck_results: RefCell<ty::TypeckResults<'tcx>>, @@ -78,11 +77,7 @@ impl<'tcx> TypeckRootCtxt<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; - let infcx = tcx - .infer_ctxt() - .ignoring_regions() - .with_opaque_type_inference(DefiningAnchor::bind(tcx, def_id)) - .build(); + let infcx = tcx.infer_ctxt().ignoring_regions().with_opaque_type_inference(def_id).build(); let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner)); TypeckRootCtxt { diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 94088216c02..f2222eec76a 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -75,7 +75,7 @@ impl<'tcx> InferCtxt<'tcx> { pub fn fork_with_intercrate(&self, intercrate: bool) -> Self { Self { tcx: self.tcx, - defining_use_anchor: self.defining_use_anchor, + defining_opaque_types: self.defining_opaque_types, considering_regions: self.considering_regions, skip_leak_check: self.skip_leak_check, inner: self.inner.clone(), diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 9f70fee993d..825c3bf82fc 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -42,7 +42,7 @@ impl<'tcx> InferCtxt<'tcx> { V: TypeFoldable<TyCtxt<'tcx>>, { let (param_env, value) = value.into_parts(); - let param_env = self.tcx.canonical_param_env_cache.get_or_insert( + let mut param_env = self.tcx.canonical_param_env_cache.get_or_insert( self.tcx, param_env, query_state, @@ -59,6 +59,8 @@ impl<'tcx> InferCtxt<'tcx> { }, ); + param_env.defining_opaque_types = self.defining_opaque_types; + Canonicalizer::canonicalize_with_base( param_env, value, @@ -440,6 +442,7 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Canonicalizer<'cx, 'tcx> { | ty::Tuple(..) | ty::Alias(..) | ty::Foreign(..) + | ty::Pat(..) | ty::Param(..) => { if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) @@ -540,6 +543,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), value: (), + defining_opaque_types: infcx.map(|i| i.defining_opaque_types).unwrap_or_default(), }; Canonicalizer::canonicalize_with_base( base, @@ -609,7 +613,15 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> { .max() .unwrap_or(ty::UniverseIndex::ROOT); - Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) } + assert!( + !infcx.is_some_and(|infcx| infcx.defining_opaque_types != base.defining_opaque_types) + ); + Canonical { + max_universe, + variables: canonical_variables, + value: (base.value, out_value), + defining_opaque_types: base.defining_opaque_types, + } } /// Creates a canonical variable replacing `kind` from the input, diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 9d2e065afa3..b948067e750 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -505,12 +505,9 @@ impl<'tcx> InferCtxt<'tcx> { let b = instantiate_value(self.tcx, &result_args, b); debug!(?a, ?b, "constrain opaque type"); // We use equate here instead of, for example, just registering the - // opaque type's hidden value directly, because we may be instantiating - // a query response that was canonicalized in an InferCtxt that had - // a different defining anchor. In that case, we may have inferred - // `NonLocalOpaque := LocalOpaque` but can only instantiate it in - // the other direction as `LocalOpaque := NonLocalOpaque`. Using eq - // here allows us to try both directions (in `InferCtxt::handle_opaque_type`). + // opaque type's hidden value directly, because the hidden type may have been an inference + // variable that got constrained to the opaque type itself. In that case we want to equate + // the generic args of the opaque with the generic params of its hidden type version. obligations.extend( self.at(cause, param_env) .eq( diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs index 9a05fb1c30f..7855031e705 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs @@ -15,7 +15,7 @@ use rustc_middle::traits::{ }; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; -use rustc_span::{sym, BytePos, Span}; +use rustc_span::{sym, Span}; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, @@ -763,8 +763,14 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let mac_call = rustc_span::source_map::original_sp(last_stmt.span, blk.span); self.tcx.sess.source_map().mac_call_stmt_semi_span(mac_call)? } else { - last_stmt.span.with_lo(last_stmt.span.hi() - BytePos(1)) + self.tcx + .sess + .source_map() + .span_extend_while_whitespace(last_expr.span) + .shrink_to_hi() + .with_hi(last_stmt.span.hi()) }; + Some((span, needs_box)) } @@ -867,10 +873,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!(" {ident} ") }; let left_span = sm.span_through_char(blk.span, '{').shrink_to_hi(); - ( - sm.span_extend_while(left_span, |c| c.is_whitespace()).unwrap_or(left_span), - sugg, - ) + (sm.span_extend_while_whitespace(left_span), sugg) }; Some(SuggestRemoveSemiOrReturnBinding::Add { sp: span, code: sugg, ident: *ident }) } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6e5ed0a31cb..0b8061104ab 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -34,7 +34,7 @@ use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKin use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::traits::{select, DefiningAnchor}; +use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -243,18 +243,8 @@ impl<'tcx> InferCtxtInner<'tcx> { pub struct InferCtxt<'tcx> { pub tcx: TyCtxt<'tcx>, - /// The `DefId` of the item in whose context we are performing inference or typeck. - /// It is used to check whether an opaque type use is a defining use. - /// - /// If it is `DefiningAnchor::Bubble`, we can't resolve opaque types here and need to bubble up - /// the obligation. This frequently happens for - /// short lived InferCtxt within queries. The opaque type obligations are forwarded - /// to the outside until the end up in an `InferCtxt` for typeck or borrowck. - /// - /// Its default value is `DefiningAnchor::Bind(&[])`, which means no opaque types may be defined. - /// This way it is easier to catch errors that - /// might come up during inference or typeck. - pub defining_use_anchor: DefiningAnchor<'tcx>, + /// The `DefIds` of the opaque types that may have their hidden types constrained. + defining_opaque_types: &'tcx ty::List<LocalDefId>, /// Whether this inference context should care about region obligations in /// the root universe. Most notably, this is used during hir typeck as region @@ -401,6 +391,10 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> { self.probe_const_var(vid).ok() } + + fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> { + self.defining_opaque_types + } } /// See the `error_reporting` module for more details. @@ -615,7 +609,7 @@ impl fmt::Display for FixupError { /// Used to configure inference contexts before their creation. pub struct InferCtxtBuilder<'tcx> { tcx: TyCtxt<'tcx>, - defining_use_anchor: DefiningAnchor<'tcx>, + defining_opaque_types: &'tcx ty::List<LocalDefId>, considering_regions: bool, skip_leak_check: bool, /// Whether we are in coherence mode. @@ -630,7 +624,7 @@ impl<'tcx> TyCtxt<'tcx> { fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> { InferCtxtBuilder { tcx: self, - defining_use_anchor: DefiningAnchor::Bind(ty::List::empty()), + defining_opaque_types: ty::List::empty(), considering_regions: true, skip_leak_check: false, intercrate: false, @@ -646,8 +640,16 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// It is only meant to be called in two places, for typeck /// (via `Inherited::build`) and for the inference context used /// in mir borrowck. - pub fn with_opaque_type_inference(mut self, defining_use_anchor: DefiningAnchor<'tcx>) -> Self { - self.defining_use_anchor = defining_use_anchor; + pub fn with_opaque_type_inference(mut self, defining_anchor: LocalDefId) -> Self { + self.defining_opaque_types = self.tcx.opaque_types_defined_by(defining_anchor); + self + } + + pub fn with_defining_opaque_types( + mut self, + defining_opaque_types: &'tcx ty::List<LocalDefId>, + ) -> Self { + self.defining_opaque_types = defining_opaque_types; self } @@ -679,14 +681,14 @@ impl<'tcx> InferCtxtBuilder<'tcx> { /// the bound values in `C` to their instantiated values in `V` /// (in other words, `S(C) = V`). pub fn build_with_canonical<T>( - &mut self, + self, span: Span, canonical: &Canonical<'tcx, T>, ) -> (InferCtxt<'tcx>, T, CanonicalVarValues<'tcx>) where T: TypeFoldable<TyCtxt<'tcx>>, { - let infcx = self.build(); + let infcx = self.with_defining_opaque_types(canonical.defining_opaque_types).build(); let (value, args) = infcx.instantiate_canonical(span, canonical); (infcx, value, args) } @@ -694,7 +696,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { pub fn build(&mut self) -> InferCtxt<'tcx> { let InferCtxtBuilder { tcx, - defining_use_anchor, + defining_opaque_types, considering_regions, skip_leak_check, intercrate, @@ -702,7 +704,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { } = *self; InferCtxt { tcx, - defining_use_anchor, + defining_opaque_types, considering_regions, skip_leak_check, inner: RefCell::new(InferCtxtInner::new()), @@ -1230,6 +1232,12 @@ impl<'tcx> InferCtxt<'tcx> { self.inner.borrow().opaque_type_storage.opaque_types.clone() } + #[inline(always)] + pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool { + let Some(id) = id.into().as_local() else { return false }; + self.defining_opaque_types.contains(&id) + } + pub fn ty_to_string(&self, t: Ty<'tcx>) -> String { self.resolve_vars_if_possible(t).to_string() } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 01430e830e5..d32515425c4 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -4,11 +4,10 @@ use crate::errors::OpaqueHiddenTypeDiag; use crate::infer::{InferCtxt, InferOk}; use crate::traits::{self, PredicateObligation}; use hir::def_id::{DefId, LocalDefId}; -use hir::OpaqueTyOrigin; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::Lrc; use rustc_hir as hir; -use rustc_middle::traits::{DefiningAnchor, ObligationCause}; +use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::GenericArgKind; @@ -54,16 +53,13 @@ impl<'tcx> InferCtxt<'tcx> { } let mut obligations = vec![]; - let replace_opaque_type = |def_id: DefId| { - def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some()) - }; let value = value.fold_with(&mut BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, ct_op: |ct| ct, ty_op: |ty| match *ty.kind() { ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) - if replace_opaque_type(def_id) && !ty.has_escaping_bound_vars() => + if self.can_define_opaque_ty(def_id) && !ty.has_escaping_bound_vars() => { let def_span = self.tcx.def_span(def_id); let span = if span.contains(def_span) { def_span } else { span }; @@ -106,56 +102,52 @@ impl<'tcx> InferCtxt<'tcx> { b, )); } - match self.defining_use_anchor { - DefiningAnchor::Bind(_) => { - // Check that this is `impl Trait` type is - // declared by `parent_def_id` -- i.e., one whose - // value we are inferring. At present, this is - // always true during the first phase of - // type-check, but not always true later on during - // NLL. Once we support named opaque types more fully, - // this same scenario will be able to arise during all phases. - // - // Here is an example using type alias `impl Trait` - // that indicates the distinction we are checking for: - // - // ```rust - // mod a { - // pub type Foo = impl Iterator; - // pub fn make_foo() -> Foo { .. } - // } - // - // mod b { - // fn foo() -> a::Foo { a::make_foo() } - // } - // ``` - // - // Here, the return type of `foo` references an - // `Opaque` indeed, but not one whose value is - // presently being inferred. You can get into a - // similar situation with closure return types - // today: - // - // ```rust - // fn foo() -> impl Iterator { .. } - // fn bar() { - // let x = || foo(); // returns the Opaque assoc with `foo` - // } - // ``` - if self.opaque_type_origin(def_id).is_none() { - return None; - } - } - DefiningAnchor::Bubble => {} + // Check that this is `impl Trait` type is + // declared by `parent_def_id` -- i.e., one whose + // value we are inferring. At present, this is + // always true during the first phase of + // type-check, but not always true later on during + // NLL. Once we support named opaque types more fully, + // this same scenario will be able to arise during all phases. + // + // Here is an example using type alias `impl Trait` + // that indicates the distinction we are checking for: + // + // ```rust + // mod a { + // pub type Foo = impl Iterator; + // pub fn make_foo() -> Foo { .. } + // } + // + // mod b { + // fn foo() -> a::Foo { a::make_foo() } + // } + // ``` + // + // Here, the return type of `foo` references an + // `Opaque` indeed, but not one whose value is + // presently being inferred. You can get into a + // similar situation with closure return types + // today: + // + // ```rust + // fn foo() -> impl Iterator { .. } + // fn bar() { + // let x = || foo(); // returns the Opaque assoc with `foo` + // } + // ``` + if !self.can_define_opaque_ty(def_id) { + return None; } + if let ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }) = *b.kind() { // We could accept this, but there are various ways to handle this situation, and we don't // want to make a decision on it right now. Likely this case is so super rare anyway, that // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias { .. }) = - b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id)) + if self.can_define_opaque_ty(b_def_id) + && self.tcx.is_type_alias_impl_trait(b_def_id) { self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag { span: cause.span, @@ -367,20 +359,6 @@ impl<'tcx> InferCtxt<'tcx> { op: |r| self.member_constraint(opaque_type_key, span, concrete_ty, r, &choice_regions), }); } - - /// Returns the origin of the opaque type `def_id` if we're currently - /// in its defining scope. - #[instrument(skip(self), level = "trace", ret)] - pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option<OpaqueTyOrigin> { - let defined_opaque_types = match self.defining_use_anchor { - DefiningAnchor::Bubble => return None, - DefiningAnchor::Bind(bind) => bind, - }; - - let origin = self.tcx.opaque_type_origin(def_id); - - defined_opaque_types.contains(&def_id).then_some(origin) - } } /// Visitor that requires that (almost) all regions in the type visited outlive diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 7dd1ec32542..6bab3ad6ba3 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -93,6 +93,7 @@ fn compute_components<'tcx>( } } + ty::Pat(element, _) | ty::Array(element, _) => { // Don't look into the len const as it doesn't affect regions compute_components(tcx, element, out, visited); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 1f92cc4d763..d04d30b3cb0 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -686,18 +686,15 @@ pub fn create_global_ctxt<'tcx>( }) } -/// Runs the type-checking, region checking and other miscellaneous analysis -/// passes on the crate. -fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { +/// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. +/// This function never fails. +fn run_required_analyses(tcx: TyCtxt<'_>) { if tcx.sess.opts.unstable_opts.hir_stats { rustc_passes::hir_stats::print_hir_stats(tcx); } - #[cfg(debug_assertions)] rustc_passes::hir_id_validator::check_crate(tcx); - let sess = tcx.sess; - sess.time("misc_checking_1", || { parallel!( { @@ -733,10 +730,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } ); }); - - // passes are timed inside typeck - rustc_hir_analysis::check_crate(tcx)?; - + rustc_hir_analysis::check_crate(tcx); sess.time("MIR_borrow_checking", || { tcx.hir().par_body_owners(|def_id| { // Run unsafety check because it's responsible for stealing and @@ -745,7 +739,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { tcx.ensure().mir_borrowck(def_id) }); }); - sess.time("MIR_effect_checking", || { for def_id in tcx.hir().body_owners() { tcx.ensure().has_ffi_unwind_calls(def_id); @@ -761,16 +754,22 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { } } }); - tcx.hir().par_body_owners(|def_id| { if tcx.is_coroutine(def_id.to_def_id()) { tcx.ensure().mir_coroutine_witnesses(def_id); tcx.ensure().check_coroutine_obligations(def_id); } }); - sess.time("layout_testing", || layout_test::test_layout(tcx)); sess.time("abi_testing", || abi_test::test_abi(tcx)); +} + +/// Runs the type-checking, region checking and other miscellaneous analysis +/// passes on the crate. +fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { + run_required_analyses(tcx); + + let sess = tcx.sess; // Avoid overwhelming user with errors if borrow checking failed. // I'm not sure how helpful this is, to be honest, but it avoids a diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index b9025917d13..d2fb65b5d4f 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -846,6 +846,7 @@ fn test_unstable_options_tracking_hash() { tracked!(trap_unreachable, Some(false)); tracked!(treat_err_as_bug, NonZero::new(1)); tracked!(tune_cpu, Some(String::from("abc"))); + tracked!(ub_checks, Some(false)); tracked!(uninit_const_chunk_threshold, 123); tracked!(unleash_the_miri_inside_of_you, true); tracked!(use_ctors_section, Some(true)); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 797c0df4d73..82b90e1660a 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -299,6 +299,9 @@ lint_improper_ctypes_only_phantomdata = composed only of `PhantomData` lint_improper_ctypes_opaque = opaque types have no C equivalent +lint_improper_ctypes_pat_help = consider using the base type instead + +lint_improper_ctypes_pat_reason = pattern types have no C equivalent lint_improper_ctypes_slice_help = consider using a raw pointer instead lint_improper_ctypes_slice_reason = slices have no C equivalent diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 70c7aff3f20..8b974a461d4 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1337,8 +1337,9 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller { } declare_lint! { - /// The `unreachable_pub` lint triggers for `pub` items not reachable from - /// the crate root. + /// The `unreachable_pub` lint triggers for `pub` items not reachable from other crates - that + /// means neither directly accessible, nor reexported, nor leaked through things like return + /// types. /// /// ### Example /// diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index e2010ab3830..16e3b8c11c1 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -215,10 +215,7 @@ pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Di if let Some(deletion_span) = deletion_span { let msg = "elide the single-use lifetime"; let (use_span, replace_lt) = if elide { - let use_span = sess - .source_map() - .span_extend_while(use_span, char::is_whitespace) - .unwrap_or(use_span); + let use_span = sess.source_map().span_extend_while_whitespace(use_span); (use_span, String::new()) } else { (use_span, "'_".to_owned()) diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 1e9c60a540d..870e198d70a 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -157,6 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { | TyKind::Never | TyKind::Tup(_) | TyKind::Path(_) + | TyKind::Pat(..) | TyKind::AnonAdt(_) | TyKind::OpaqueDef(_, _, _) | TyKind::Typeof(_) diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs index cf825be7a55..ec7954536be 100644 --- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs +++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs @@ -20,7 +20,7 @@ declare_lint! { /// This functionality was removed in #97346, but then rolled back in #99860 /// because it caused regressions. /// - /// We plan on reintroducing this as a hard error, but in the mean time, + /// We plan on reintroducing this as a hard error, but in the meantime, /// this lint serves to warn and suggest fixes for any use-cases which rely /// on this behavior. /// diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 534eb60eeb0..e982842f536 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1379,6 +1379,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { help: Some(fluent::lint_improper_ctypes_char_help), }, + ty::Pat(..) => FfiUnsafe { + ty, + reason: fluent::lint_improper_ctypes_pat_reason, + help: Some(fluent::lint_improper_ctypes_pat_help), + }, + ty::Int(ty::IntTy::I128) | ty::Uint(ty::UintTy::U128) => { FfiUnsafe { ty, reason: fluent::lint_improper_ctypes_128bit, help: None } } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 30522628f46..2713690f812 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -79,6 +79,7 @@ declare_lint_pass! { PROC_MACRO_BACK_COMPAT, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, PUB_USE_OF_PRIVATE_EXTERN_CRATE, + REDUNDANT_LIFETIMES, REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE, RENAMED_AND_REMOVED_LINTS, @@ -1708,6 +1709,33 @@ declare_lint! { } declare_lint! { + /// The `redundant_lifetimes` lint detects lifetime parameters that are + /// redundant because they are equal to another named lifetime. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[deny(redundant_lifetimes)] + /// + /// // `'a = 'static`, so all usages of `'a` can be replaced with `'static` + /// pub fn bar<'a: 'static>() {} + /// + /// // `'a = 'b`, so all usages of `'b` can be replaced with `'a` + /// pub fn bar<'a: 'b, 'b: 'a>() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused lifetime parameters may signal a mistake or unfinished code. + /// Consider removing the parameter. + pub REDUNDANT_LIFETIMES, + Allow, + "detects lifetime parameters that are redundant because they are equal to some other named lifetime" +} + +declare_lint! { /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an /// inference variable. /// @@ -4311,7 +4339,6 @@ declare_lint! { /// ### Example /// /// ```rust,compile_fail - /// # #![feature(type_privacy_lints)] /// # #![allow(unused)] /// #![deny(unnameable_types)] /// mod m { @@ -4328,10 +4355,14 @@ declare_lint! { /// /// It is often expected that if you can obtain an object of type `T`, then /// you can name the type `T` as well, this lint attempts to enforce this rule. + /// The recommended action is to either reexport the type properly to make it nameable, + /// or document that users are not supposed to be able to name it for one reason or another. + /// + /// Besides types, this lint applies to traits because traits can also leak through signatures, + /// and you may obtain objects of their `dyn Trait` or `impl Trait` types. pub UNNAMEABLE_TYPES, Allow, "effective visibility of a type is larger than the area in which it can be named", - @feature_gate = sym::type_privacy_lints; } declare_lint! { diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index e2c0ec90c7c..66ca94d1d9c 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -112,28 +112,10 @@ fn main() { restore_library_path(); - let target = env::var("TARGET").expect("TARGET was not set"); let llvm_config = - tracked_env_var_os("LLVM_CONFIG").map(|x| Some(PathBuf::from(x))).unwrap_or_else(|| { - if let Some(dir) = tracked_env_var_os("CARGO_TARGET_DIR").map(PathBuf::from) { - let to_test = dir - .parent() - .unwrap() - .parent() - .unwrap() - .join(&target) - .join("llvm/bin/llvm-config"); - if Command::new(&to_test).output().is_ok() { - return Some(to_test); - } - } - None - }); + PathBuf::from(tracked_env_var_os("LLVM_CONFIG").expect("LLVM_CONFIG was not set")); - if let Some(llvm_config) = &llvm_config { - println!("cargo:rerun-if-changed={}", llvm_config.display()); - } - let llvm_config = llvm_config.unwrap_or_else(|| PathBuf::from("llvm-config")); + println!("cargo:rerun-if-changed={}", llvm_config.display()); // Test whether we're cross-compiling LLVM. This is a pretty rare case // currently where we're producing an LLVM for a different platform than diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 40723ff9f5e..64e6c18092f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -147,7 +147,7 @@ LLVMRustArchiveChildName(LLVMRustArchiveChildConstRef Child, size_t *Size) { Expected<StringRef> NameOrErr = Child->getName(); if (!NameOrErr) { // rustc_codegen_llvm currently doesn't use this error string, but it might be - // useful in the future, and in the mean time this tells LLVM that the + // useful in the future, and in the meantime this tells LLVM that the // error was not ignored and that it shouldn't abort the process. LLVMRustSetLastError(toString(NameOrErr.takeError()).c_str()); return nullptr; diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 8ec1f5a99e7..37c2da4c23a 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -817,7 +817,7 @@ extern "C" uint32_t LLVMRustVersionMinor() { return LLVM_VERSION_MINOR; } extern "C" uint32_t LLVMRustVersionMajor() { return LLVM_VERSION_MAJOR; } -extern "C" void LLVMRustAddModuleFlag( +extern "C" void LLVMRustAddModuleFlagU32( LLVMModuleRef M, Module::ModFlagBehavior MergeBehavior, const char *Name, @@ -825,6 +825,16 @@ extern "C" void LLVMRustAddModuleFlag( unwrap(M)->addModuleFlag(MergeBehavior, Name, Value); } +extern "C" void LLVMRustAddModuleFlagString( + LLVMModuleRef M, + Module::ModFlagBehavior MergeBehavior, + const char *Name, + const char *Value, + size_t ValueLen) { + unwrap(M)->addModuleFlag(MergeBehavior, Name, + MDString::get(unwrap(M)->getContext(), StringRef(Value, ValueLen))); +} + extern "C" bool LLVMRustHasModuleFlag(LLVMModuleRef M, const char *Name, size_t Len) { return unwrap(M)->getModuleFlag(StringRef(Name, Len)) != nullptr; @@ -1524,8 +1534,8 @@ extern "C" LLVMValueRef LLVMRustBuildCall(LLVMBuilderRef B, LLVMTypeRef Ty, LLVM } extern "C" LLVMValueRef LLVMRustGetInstrProfIncrementIntrinsic(LLVMModuleRef M) { - return wrap(llvm::Intrinsic::getDeclaration(unwrap(M), - (llvm::Intrinsic::ID)llvm::Intrinsic::instrprof_increment)); + return wrap(llvm::Intrinsic::getDeclaration( + unwrap(M), llvm::Intrinsic::instrprof_increment)); } extern "C" LLVMValueRef LLVMRustBuildMemCpy(LLVMBuilderRef B, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index b69a295f010..2935d5b8f63 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{self, TyCtxt}; use rustc_middle::util::Providers; use rustc_session::cstore::{CrateStore, ExternCrate}; use rustc_session::{Session, StableCrateId}; -use rustc_span::hygiene::{ExpnHash, ExpnId}; +use rustc_span::hygiene::ExpnId; use rustc_span::symbol::{kw, Symbol}; use rustc_span::Span; @@ -378,6 +378,7 @@ provide! { tcx, def_id, other, cdata, } pub(in crate::rmeta) fn provide(providers: &mut Providers) { + provide_cstore_hooks(providers); // FIXME(#44234) - almost all of these queries have no sub-queries and // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about @@ -649,26 +650,27 @@ impl CrateStore for CStore { fn def_path_hash(&self, def: DefId) -> DefPathHash { self.get_crate_data(def.krate).def_path_hash(def.index) } +} - fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId { - let def_index = self.get_crate_data(cnum).def_path_hash_to_def_index(hash); +fn provide_cstore_hooks(providers: &mut Providers) { + providers.hooks.def_path_hash_to_def_id_extern = |tcx, hash, stable_crate_id| { + // If this is a DefPathHash from an upstream crate, let the CrateStore map + // it to a DefId. + let cstore = CStore::from_tcx(tcx.tcx); + let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); + let def_index = cstore.get_crate_data(cnum).def_path_hash_to_def_index(hash); DefId { krate: cnum, index: def_index } - } - - fn expn_hash_to_expn_id( - &self, - sess: &Session, - cnum: CrateNum, - index_guess: u32, - hash: ExpnHash, - ) -> ExpnId { - self.get_crate_data(cnum).expn_hash_to_expn_id(sess, index_guess, hash) - } + }; - fn import_source_files(&self, sess: &Session, cnum: CrateNum) { - let cdata = self.get_crate_data(cnum); + providers.hooks.expn_hash_to_expn_id = |tcx, cnum, index_guess, hash| { + let cstore = CStore::from_tcx(tcx.tcx); + cstore.get_crate_data(cnum).expn_hash_to_expn_id(tcx.sess, index_guess, hash) + }; + providers.hooks.import_source_files = |tcx, cnum| { + let cstore = CStore::from_tcx(tcx.tcx); + let cdata = cstore.get_crate_data(cnum); for file_index in 0..cdata.root.source_map.size() { - cdata.imported_source_file(file_index as u32, sess); + cdata.imported_source_file(file_index as u32, tcx.sess); } - } + }; } diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index bd11b3eb04c..13719268737 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -90,6 +90,7 @@ macro_rules! arena_types { [decode] attribute: rustc_ast::Attribute, [] name_set: rustc_data_structures::unord::UnordSet<rustc_span::symbol::Symbol>, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::symbol::Symbol>, + [] pats: rustc_middle::ty::PatternKind<'tcx>, // Note that this deliberately duplicates items in the `rustc_hir::arena`, // since we need to allocate this type on both the `rustc_hir` arena diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index aa2cddad093..f7ce15d0a8d 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -6,8 +6,10 @@ use crate::mir; use crate::query::TyCtxtAt; use crate::ty::{Ty, TyCtxt}; -use rustc_span::def_id::LocalDefId; -use rustc_span::DUMMY_SP; +use rustc_hir::def_id::{DefId, DefPathHash}; +use rustc_session::StableCrateId; +use rustc_span::def_id::{CrateNum, LocalDefId}; +use rustc_span::{ExpnHash, ExpnId, DUMMY_SP}; macro_rules! declare_hooks { ($($(#[$attr:meta])*hook $name:ident($($arg:ident: $K:ty),*) -> $V:ty;)*) => { @@ -16,7 +18,6 @@ macro_rules! declare_hooks { $( $(#[$attr])* #[inline(always)] - #[must_use] pub fn $name(self, $($arg: $K,)*) -> $V { self.at(DUMMY_SP).$name($($arg,)*) @@ -28,7 +29,6 @@ macro_rules! declare_hooks { $( $(#[$attr])* #[inline(always)] - #[must_use] #[instrument(level = "debug", skip(self), ret)] pub fn $name(self, $($arg: $K,)*) -> $V { @@ -83,4 +83,23 @@ declare_hooks! { /// You do not want to call this yourself, instead use the cached version /// via `mir_built` hook build_mir(key: LocalDefId) -> mir::Body<'tcx>; + + + /// Imports all `SourceFile`s from the given crate into the current session. + /// This normally happens automatically when we decode a `Span` from + /// that crate's metadata - however, the incr comp cache needs + /// to trigger this manually when decoding a foreign `Span` + hook import_source_files(key: CrateNum) -> (); + + hook expn_hash_to_expn_id( + cnum: CrateNum, + index_guess: u32, + hash: ExpnHash + ) -> ExpnId; + + /// Converts a `DefPathHash` to its corresponding `DefId` in the current compilation + /// session, if it still exists. This is used during incremental compilation to + /// turn a deserialized `DefPathHash` into its current `DefId`. + /// Will fetch a DefId from a DefPathHash for a foreign crate. + hook def_path_hash_to_def_id_extern(hash: DefPathHash, stable_crate_id: StableCrateId) -> DefId; } diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index acea89e4aab..62d7b7c28d1 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -153,11 +153,6 @@ pub struct QueryResponse<'tcx, R> { pub var_values: CanonicalVarValues<'tcx>, pub region_constraints: QueryRegionConstraints<'tcx>, pub certainty: Certainty, - /// List of opaque types which we tried to compare to another type. - /// Inside the query we don't know yet whether the opaque type actually - /// should get its hidden type inferred. So we bubble the opaque type - /// and the type it was compared against upwards and let the query caller - /// handle it. pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, pub value: R, } @@ -330,6 +325,7 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { max_universe: ty::UniverseIndex::ROOT, variables: List::empty(), value: key, + defining_opaque_types: ty::List::empty(), }; } @@ -340,6 +336,14 @@ impl<'tcx> CanonicalParamEnvCache<'tcx> { match self.map.borrow().entry(key) { Entry::Occupied(e) => { let (canonical, var_values) = e.get(); + if cfg!(debug_assertions) { + let mut state = state.clone(); + let rerun_canonical = canonicalize_op(tcx, key, &mut state); + assert_eq!(rerun_canonical, *canonical); + let OriginalQueryValues { var_values: rerun_var_values, universe_map } = state; + assert_eq!(universe_map.len(), 1); + assert_eq!(**var_values, *rerun_var_values); + } state.var_values.extend_from_slice(var_values); *canonical } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index ad166620bcc..601bfc770f4 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -30,7 +30,6 @@ pub use rustc_ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::graph::dominators::Dominators; -use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_index::bit_set::BitSet; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_serialize::{Decodable, Encodable}; @@ -687,57 +686,6 @@ impl<'tcx> Body<'tcx> { self.injection_phase.is_some() } - /// Finds which basic blocks are actually reachable for a specific - /// monomorphization of this body. - /// - /// This is allowed to have false positives; just because this says a block - /// is reachable doesn't mean that's necessarily true. It's thus always - /// legal for this to return a filled set. - /// - /// Regardless, the [`BitSet::domain_size`] of the returned set will always - /// exactly match the number of blocks in the body so that `contains` - /// checks can be done without worrying about panicking. - /// - /// This is mostly useful because it lets us skip lowering the `false` side - /// of `if <T as Trait>::CONST`, as well as `intrinsics::debug_assertions`. - pub fn reachable_blocks_in_mono( - &self, - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - ) -> BitSet<BasicBlock> { - let mut set = BitSet::new_empty(self.basic_blocks.len()); - self.reachable_blocks_in_mono_from(tcx, instance, &mut set, START_BLOCK); - set - } - - fn reachable_blocks_in_mono_from( - &self, - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - set: &mut BitSet<BasicBlock>, - bb: BasicBlock, - ) { - if !set.insert(bb) { - return; - } - - let data = &self.basic_blocks[bb]; - - if let Some((bits, targets)) = Self::try_const_mono_switchint(tcx, instance, data) { - let target = targets.target_for_value(bits); - ensure_sufficient_stack(|| { - self.reachable_blocks_in_mono_from(tcx, instance, set, target) - }); - return; - } - - for target in data.terminator().successors() { - ensure_sufficient_stack(|| { - self.reachable_blocks_in_mono_from(tcx, instance, set, target) - }); - } - } - /// If this basic block ends with a [`TerminatorKind::SwitchInt`] for which we can evaluate the /// dimscriminant in monomorphization, we return the discriminant bits and the /// [`SwitchTargets`], just so the caller doesn't also have to match on the terminator. @@ -777,8 +725,8 @@ impl<'tcx> Body<'tcx> { // _1 = const _ // SwitchInt(_1) // - // And MIR for if intrinsics::debug_assertions() looks like this: - // _1 = cfg!(debug_assertions) + // And MIR for if intrinsics::ub_checks() looks like this: + // _1 = UbChecks() // SwitchInt(_1) // // So we're going to try to recognize this pattern. @@ -799,9 +747,7 @@ impl<'tcx> Body<'tcx> { } match rvalue { - Rvalue::NullaryOp(NullOp::UbChecks, _) => { - Some((tcx.sess.opts.debug_assertions as u128, targets)) - } + Rvalue::NullaryOp(NullOp::UbChecks, _) => Some((tcx.sess.ub_checks() as u128, targets)), Rvalue::Use(Operand::Constant(constant)) => { let bits = eval_mono_const(constant); Some((bits, targets)) diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index f116347cc2b..58a27c1f9ef 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -85,6 +85,12 @@ impl SwitchTargets { self.values.push(value); self.targets.insert(self.targets.len() - 1, bb); } + + /// Returns true if all targets (including the fallback target) are distinct. + #[inline] + pub fn is_distinct(&self) -> bool { + self.targets.iter().collect::<FxHashSet<_>>().len() == self.targets.len() + } } pub struct SwitchTargetsIter<'a> { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 0a938bcd315..245e9096bad 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -245,7 +245,7 @@ pub fn reachable<'a, 'tcx>( /// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`. pub fn reachable_as_bitset(body: &Body<'_>) -> BitSet<BasicBlock> { let mut iter = preorder(body); - iter.by_ref().for_each(drop); + while let Some(_) = iter.next() {} iter.visited } @@ -279,3 +279,97 @@ pub fn reverse_postorder<'a, 'tcx>( { body.basic_blocks.reverse_postorder().iter().map(|&bb| (bb, &body.basic_blocks[bb])) } + +/// Traversal of a [`Body`] that tries to avoid unreachable blocks in a monomorphized [`Instance`]. +/// +/// This is allowed to have false positives; blocks may be visited even if they are not actually +/// reachable. +/// +/// Such a traversal is mostly useful because it lets us skip lowering the `false` side +/// of `if <T as Trait>::CONST`, as well as [`NullOp::UbChecks`]. +/// +/// [`NullOp::UbChecks`]: rustc_middle::mir::NullOp::UbChecks +pub fn mono_reachable<'a, 'tcx>( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> MonoReachable<'a, 'tcx> { + MonoReachable::new(body, tcx, instance) +} + +/// [`MonoReachable`] internally accumulates a [`BitSet`] of visited blocks. This is just a +/// convenience function to run that traversal then extract its set of reached blocks. +pub fn mono_reachable_as_bitset<'a, 'tcx>( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> BitSet<BasicBlock> { + let mut iter = mono_reachable(body, tcx, instance); + while let Some(_) = iter.next() {} + iter.visited +} + +pub struct MonoReachable<'a, 'tcx> { + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + visited: BitSet<BasicBlock>, + // Other traversers track their worklist in a Vec. But we don't care about order, so we can + // store ours in a BitSet and thus save allocations because BitSet has a small size + // optimization. + worklist: BitSet<BasicBlock>, +} + +impl<'a, 'tcx> MonoReachable<'a, 'tcx> { + pub fn new( + body: &'a Body<'tcx>, + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + ) -> MonoReachable<'a, 'tcx> { + let mut worklist = BitSet::new_empty(body.basic_blocks.len()); + worklist.insert(START_BLOCK); + MonoReachable { + body, + tcx, + instance, + visited: BitSet::new_empty(body.basic_blocks.len()), + worklist, + } + } + + fn add_work(&mut self, blocks: impl IntoIterator<Item = BasicBlock>) { + for block in blocks.into_iter() { + if !self.visited.contains(block) { + self.worklist.insert(block); + } + } + } +} + +impl<'a, 'tcx> Iterator for MonoReachable<'a, 'tcx> { + type Item = (BasicBlock, &'a BasicBlockData<'tcx>); + + fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { + while let Some(idx) = self.worklist.iter().next() { + self.worklist.remove(idx); + if !self.visited.insert(idx) { + continue; + } + + let data = &self.body[idx]; + + if let Some((bits, targets)) = + Body::try_const_mono_switchint(self.tcx, self.instance, data) + { + let target = targets.target_for_value(bits); + self.add_work([target]); + } else { + self.add_work(data.terminator().successors()); + } + + return Some((idx, data)); + } + + None + } +} diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index d3da49c26a2..320d49ea646 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -67,6 +67,10 @@ impl<T> EraseType for &'_ ty::List<T> { type Result = [u8; size_of::<&'static ty::List<()>>()]; } +impl<T> EraseType for &'_ ty::ListWithCachedTypeInfo<T> { + type Result = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()]; +} + impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> { type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()]; } diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 9cbc4d10146..c1548eb99f5 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -432,7 +432,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) { } } -impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> { +impl<'tcx> Key for ty::Clauses<'tcx> { type Cache<V> = DefaultCache<Self, V>; fn default_span(&self, _: TyCtxt<'_>) -> Span { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 62a60a650ec..5ef7a20f460 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -398,15 +398,15 @@ rustc_queries! { /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. - query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + query item_bounds(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> { desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) } } - query item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + query item_super_predicates(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> { desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } } - query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> { + query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> { desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) } } @@ -2156,7 +2156,7 @@ rustc_queries! { desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) } } - query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Clause<'tcx>>) -> &'tcx ty::List<ty::Clause<'tcx>> { + query reveal_opaque_types_in_bounds(key: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> { desc { "revealing opaque types in `{:?}`", key } } diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index 8f02b3121ac..db1b5a74f0a 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -492,9 +492,7 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> { // expansion, so we use `import_source_files` to ensure that the foreign // source files are actually imported before we call `source_file_by_stable_id`. if source_file_cnum != LOCAL_CRATE { - self.tcx - .cstore_untracked() - .import_source_files(self.tcx.sess, source_file_cnum); + self.tcx.import_source_files(source_file_cnum); } source_map @@ -634,12 +632,7 @@ impl<'a, 'tcx> SpanDecoder for CacheDecoder<'a, 'tcx> { expn_id } else { let index_guess = self.foreign_expn_data[&hash]; - self.tcx.cstore_untracked().expn_hash_to_expn_id( - self.tcx.sess, - krate, - index_guess, - hash, - ) + self.tcx.expn_hash_to_expn_id(krate, index_guess, hash) }; debug_assert_eq!(expn_id.krate, krate); diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 8cb4ee7bd41..6555a687152 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -338,10 +338,11 @@ macro_rules! define_callbacks { pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>; - // Ensure that keys grow no larger than 64 bytes + // Ensure that keys grow no larger than 72 bytes by accident. + // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))] const _: () = { - if mem::size_of::<Key<'static>>() > 64 { + if mem::size_of::<Key<'static>>() > 72 { panic!("{}", concat!( "the query `", stringify!($name), @@ -352,7 +353,8 @@ macro_rules! define_callbacks { } }; - // Ensure that values grow no larger than 64 bytes + // Ensure that values grow no larger than 64 bytes by accident. + // Increase this limit if necessary, but do try to keep the size low if possible #[cfg(all(any(target_arch = "x86_64", target_arch="aarch64"), target_pointer_width = "64"))] const _: () = { if mem::size_of::<Value<'static>>() > 64 { diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index ee816791919..d51e86c909c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -12,8 +12,8 @@ pub mod util; use crate::infer::canonical::Canonical; use crate::mir::ConstraintCategory; use crate::ty::abstract_const::NotConstEvaluatable; +use crate::ty::GenericArgsRef; use crate::ty::{self, AdtKind, Ty}; -use crate::ty::{GenericArgsRef, TyCtxt}; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, Diag, EmissionGuarantee}; @@ -997,33 +997,3 @@ pub enum CodegenObligationError { Unimplemented, FulfillmentError, } - -/// Defines the treatment of opaque types in a given inference context. -/// -/// This affects both what opaques are allowed to be defined, but also whether -/// opaques are replaced with inference vars eagerly in the old solver (e.g. -/// in projection, and in the signature during function type-checking). -#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] -pub enum DefiningAnchor<'tcx> { - /// Define opaques which are in-scope of the current item being analyzed. - /// Also, eagerly replace these opaque types in `replace_opaque_types_with_inference_vars`. - /// - /// If the list is empty, do not allow any opaques to be defined. This is used to catch type mismatch - /// errors when handling opaque types, and also should be used when we would - /// otherwise reveal opaques (such as [`Reveal::All`] reveal mode). - Bind(&'tcx ty::List<LocalDefId>), - /// In contexts where we don't currently know what opaques are allowed to be - /// defined, such as (old solver) canonical queries, we will simply allow - /// opaques to be defined, but "bubble" them up in the canonical response or - /// otherwise treat them to be handled later. - /// - /// We do not eagerly replace opaque types in `replace_opaque_types_with_inference_vars`, - /// which may affect what predicates pass and fail in the old trait solver. - Bubble, -} - -impl<'tcx> DefiningAnchor<'tcx> { - pub fn bind(tcx: TyCtxt<'tcx>, item: LocalDefId) -> Self { - Self::Bind(tcx.opaque_types_defined_by(item)) - } -} diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 6dcea2aaff1..13504c6ae93 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -4,7 +4,7 @@ use rustc_span::def_id::DefId; use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints}; use crate::traits::query::NoSolution; -use crate::traits::{Canonical, DefiningAnchor}; +use crate::traits::Canonical; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, @@ -114,7 +114,6 @@ impl MaybeCause { #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct QueryInput<'tcx, T> { pub goal: Goal<'tcx, T>, - pub anchor: DefiningAnchor<'tcx>, pub predefined_opaques_in_body: PredefinedOpaques<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 7db64504f85..95d1e08b58b 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -45,7 +45,7 @@ impl UpvarId { /// Information describing the capture of an upvar. This is computed /// during `typeck`, specifically by `regionck`. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(Eq, PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub enum UpvarCapture { /// Upvar is captured by value. This is always true when the @@ -73,7 +73,7 @@ pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureLis pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>; /// A composite describing a `Place` that is captured by a closure. -#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)] +#[derive(Eq, PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub struct CapturedPlace<'tcx> { /// Name and span where the binding happens. @@ -192,7 +192,7 @@ impl<'tcx> CapturedPlace<'tcx> { #[derive(Copy, Clone, Debug, HashStable)] pub struct ClosureTypeInfo<'tcx> { user_provided_sig: ty::CanonicalPolyFnSig<'tcx>, - captures: &'tcx [&'tcx ty::CapturedPlace<'tcx>], + captures: &'tcx ty::List<&'tcx ty::CapturedPlace<'tcx>>, kind_origin: Option<&'tcx (Span, HirPlace<'tcx>)>, } @@ -201,7 +201,7 @@ fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo let typeck_results = tcx.typeck(def); let user_provided_sig = typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); - let captures = tcx.arena.alloc_from_iter(captures); + let captures = tcx.mk_captures_from_iter(captures); let hir_id = tcx.local_def_id_to_hir_id(def); let kind_origin = typeck_results.closure_kind_origins().get(hir_id); ClosureTypeInfo { user_provided_sig, captures, kind_origin } @@ -253,7 +253,7 @@ pub fn is_ancestor_or_same_capture( /// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move) /// for a particular capture as well as identifying the part of the source code /// that triggered this capture to occur. -#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)] +#[derive(Eq, PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub struct CaptureInfo { /// Expr Id pointing to use that resulted in selecting the current capture kind @@ -332,7 +332,7 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc curr_string } -#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)] +#[derive(Eq, Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable, Hash)] #[derive(TypeFoldable, TypeVisitable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index e7a1679b151..c0effe9804c 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -148,6 +148,12 @@ impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Const<'tcx> { } } +impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Pattern<'tcx> { + fn encode(&self, e: &mut E) { + self.0.0.encode(e); + } +} + impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ConstAllocation<'tcx> { fn encode(&self, e: &mut E) { self.inner().encode(e) @@ -364,6 +370,12 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> { } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Pattern<'tcx> { + fn decode(decoder: &mut D) -> Self { + decoder.interner().mk_pat(Decodable::decode(decoder)) + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] { fn decode(decoder: &mut D) -> &'tcx Self { decoder @@ -414,7 +426,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty } } -impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Clause<'tcx>> { +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> + for ty::ListWithCachedTypeInfo<ty::Clause<'tcx>> +{ fn decode(decoder: &mut D) -> &'tcx Self { let len = decoder.read_usize(); decoder.interner().mk_clauses_from_iter( @@ -441,6 +455,12 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<Lo } } +impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for &'tcx ty::List<LocalDefId> { + fn decode(d: &mut D) -> Self { + RefDecodable::decode(d) + } +} + impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<(VariantIdx, FieldIdx)> { @@ -461,7 +481,7 @@ impl_decodable_via_ref! { &'tcx mir::BorrowCheckResult<'tcx>, &'tcx mir::coverage::CodeRegion, &'tcx ty::List<ty::BoundVariableKind>, - &'tcx ty::List<ty::Clause<'tcx>>, + &'tcx ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>, &'tcx ty::List<FieldIdx>, &'tcx ty::List<(VariantIdx, FieldIdx)>, } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 75deffe6957..6275c5d2a11 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -25,10 +25,11 @@ use crate::traits::solve::{ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData, }; use crate::ty::{ - self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind, - ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate, - PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, - TyKind, TyVid, TypeVisitable, Visibility, + self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData, + GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern, + PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, + Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, + Visibility, }; use crate::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_ast::{self as ast, attr}; @@ -84,6 +85,7 @@ use std::ops::{Bound, Deref}; #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; + type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; type GenericArg = ty::GenericArg<'tcx>; @@ -95,6 +97,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type CanonicalVars = CanonicalVarInfos<'tcx>; type Ty = Ty<'tcx>; + type Pat = Pattern<'tcx>; type Tys = &'tcx List<Ty<'tcx>>; type AliasTy = ty::AliasTy<'tcx>; type ParamTy = ParamTy; @@ -130,6 +133,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type SubtypePredicate = ty::SubtypePredicate<'tcx>; type CoercePredicate = ty::CoercePredicate<'tcx>; type ClosureKind = ty::ClosureKind; + type Clauses = ty::Clauses<'tcx>; fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars { self.mk_canonical_var_infos(infos) @@ -152,10 +156,11 @@ pub struct CtxtInterners<'tcx> { region: InternedSet<'tcx, RegionKind<'tcx>>, poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>, predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>, - clauses: InternedSet<'tcx, List<Clause<'tcx>>>, + clauses: InternedSet<'tcx, ListWithCachedTypeInfo<Clause<'tcx>>>, projs: InternedSet<'tcx, List<ProjectionKind>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>, + pat: InternedSet<'tcx, PatternKind<'tcx>>, const_allocation: InternedSet<'tcx, Allocation>, bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>, layout: InternedSet<'tcx, LayoutS<FieldIdx, VariantIdx>>, @@ -164,6 +169,7 @@ pub struct CtxtInterners<'tcx> { predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List<FieldIdx>>, local_def_ids: InternedSet<'tcx, List<LocalDefId>>, + captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, offset_of: InternedSet<'tcx, List<(VariantIdx, FieldIdx)>>, } @@ -183,6 +189,7 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), + pat: Default::default(), const_allocation: Default::default(), bound_variable_kinds: Default::default(), layout: Default::default(), @@ -191,6 +198,7 @@ impl<'tcx> CtxtInterners<'tcx> { predefined_opaques_in_body: Default::default(), fields: Default::default(), local_def_ids: Default::default(), + captures: Default::default(), offset_of: Default::default(), } } @@ -286,6 +294,24 @@ impl<'tcx> CtxtInterners<'tcx> { .0, )) } + + fn intern_clauses(&self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> { + if clauses.is_empty() { + ListWithCachedTypeInfo::empty() + } else { + self.clauses + .intern_ref(clauses, || { + let flags = super::flags::FlagComputation::for_clauses(clauses); + + InternedInSet(ListWithCachedTypeInfo::from_arena( + &*self.arena, + flags.into(), + clauses, + )) + }) + .0 + } + } } // For these preinterned values, an alternative would be to have @@ -731,7 +757,7 @@ pub struct GlobalCtxt<'tcx> { impl<'tcx> GlobalCtxt<'tcx> { /// Installs `self` in a `TyCtxt` and `ImplicitCtxt` for the duration of /// `f`. - pub fn enter<'a: 'tcx, F, R>(&'a self, f: F) -> R + pub fn enter<F, R>(&'tcx self, f: F) -> R where F: FnOnce(TyCtxt<'tcx>) -> R, { @@ -1139,11 +1165,7 @@ impl<'tcx> TyCtxt<'tcx> { .local_def_path_hash_to_def_id(hash, err_msg) .to_def_id() } else { - // If this is a DefPathHash from an upstream crate, let the CrateStore map - // it to a DefId. - let cstore = &*self.cstore_untracked(); - let cnum = cstore.stable_crate_id_to_crate_num(stable_crate_id); - cstore.def_path_hash_to_def_id(cnum, hash) + self.def_path_hash_to_def_id_extern(hash, stable_crate_id) } } @@ -1559,6 +1581,7 @@ macro_rules! nop_list_lift { nop_lift! {type_; Ty<'a> => Ty<'tcx>} nop_lift! {region; Region<'a> => Region<'tcx>} nop_lift! {const_; Const<'a> => Const<'tcx>} +nop_lift! {pat; Pattern<'a> => Pattern<'tcx>} nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>} nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>} nop_lift! {predicate; Clause<'a> => Clause<'tcx>} @@ -1696,6 +1719,7 @@ impl<'tcx> TyCtxt<'tcx> { Param, Infer, Alias, + Pat, Foreign )?; @@ -1783,6 +1807,29 @@ impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> { } } +impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> { + fn borrow(&self) -> &[T] { + &self.0[..] + } +} + +impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> { + fn eq(&self, other: &InternedInSet<'tcx, ListWithCachedTypeInfo<T>>) -> bool { + // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals + // `x == y`. + self.0[..] == other.0[..] + } +} + +impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {} + +impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> { + fn hash<H: Hasher>(&self, s: &mut H) { + // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. + self.0[..].hash(s) + } +} + macro_rules! direct_interners { ($($name:ident: $vis:vis $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => { $(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> { @@ -1824,6 +1871,7 @@ macro_rules! direct_interners { // crate only, and have a corresponding `mk_` function. direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, + pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, 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>, @@ -1841,7 +1889,7 @@ macro_rules! slice_interners { List::empty() } else { self.interners.$field.intern_ref(v, || { - InternedInSet(List::from_arena(&*self.arena, v)) + InternedInSet(List::from_arena(&*self.arena, (), v)) }).0 } })+ @@ -1858,12 +1906,12 @@ slice_interners!( type_lists: pub mk_type_list(Ty<'tcx>), canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>), poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>), - clauses: intern_clauses(Clause<'tcx>), projs: pub mk_projs(ProjectionKind), place_elems: pub mk_place_elems(PlaceElem<'tcx>), bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind), fields: pub mk_fields(FieldIdx), local_def_ids: intern_local_def_ids(LocalDefId), + captures: intern_captures(&'tcx ty::CapturedPlace<'tcx>), offset_of: pub mk_offset_of((VariantIdx, FieldIdx)), ); @@ -2163,11 +2211,11 @@ impl<'tcx> TyCtxt<'tcx> { self.intern_poly_existential_predicates(eps) } - pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> { + pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> { // FIXME consider asking the input slice to be sorted to avoid // re-interning permutations, in which case that would be asserted // here. - self.intern_clauses(clauses) + self.interners.intern_clauses(clauses) } pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> { @@ -2185,6 +2233,17 @@ impl<'tcx> TyCtxt<'tcx> { T::collect_and_apply(iter, |xs| self.mk_local_def_ids(xs)) } + pub fn mk_captures_from_iter<I, T>(self, iter: I) -> T::Output + where + I: Iterator<Item = T>, + T: CollectAndApply< + &'tcx ty::CapturedPlace<'tcx>, + &'tcx List<&'tcx ty::CapturedPlace<'tcx>>, + >, + { + T::collect_and_apply(iter, |xs| self.intern_captures(xs)) + } + pub fn mk_const_list_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, @@ -2231,7 +2290,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output where I: Iterator<Item = T>, - T: CollectAndApply<Clause<'tcx>, &'tcx List<Clause<'tcx>>>, + T: CollectAndApply<Clause<'tcx>, Clauses<'tcx>>, { T::collect_and_apply(iter, |xs| self.mk_clauses(xs)) } diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index ee18647cdd8..cc1d6e50f6d 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -5,13 +5,13 @@ use std::fmt::Write; use std::ops::ControlFlow; use crate::ty::{ - AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, PolyTraitPredicate, - Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, - TypeVisitor, + self, AliasTy, Const, ConstKind, FallibleTypeFolder, InferConst, InferTy, Opaque, + PolyTraitPredicate, Projection, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diag, DiagArgValue, IntoDiagArg}; +use rustc_errors::{into_diag_arg_using_display, Applicability, Diag, DiagArgValue, IntoDiagArg}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -19,10 +19,9 @@ use rustc_hir::{PredicateOrigin, WherePredicate}; use rustc_span::{BytePos, Span}; use rustc_type_ir::TyKind::*; -impl<'tcx> IntoDiagArg for Ty<'tcx> { - fn into_diag_arg(self) -> DiagArgValue { - self.to_string().into_diag_arg() - } +into_diag_arg_using_display! { + Ty<'_>, + ty::Region<'_>, } impl<'tcx> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 09586a95f1c..ce85c28ece8 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -285,6 +285,7 @@ impl<'tcx> Ty<'tcx> { ty::Adt(def, _) => def.descr().into(), ty::Foreign(_) => "extern type".into(), ty::Array(..) => "array".into(), + ty::Pat(..) => "pattern type".into(), ty::Slice(_) => "slice".into(), ty::RawPtr(_, _) => "raw pointer".into(), ty::Ref(.., mutbl) => match mutbl { diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs index 5b257cdfd86..7c925d5fbb6 100644 --- a/compiler/rustc_middle/src/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -120,6 +120,7 @@ pub fn simplify_type<'tcx>( ty::Str => Some(SimplifiedType::Str), ty::Array(..) => Some(SimplifiedType::Array), ty::Slice(..) => Some(SimplifiedType::Slice), + ty::Pat(ty, ..) => simplify_type(tcx, ty, treat_params), ty::RawPtr(_, mutbl) => Some(SimplifiedType::Ptr(mutbl)), ty::Dynamic(trait_info, ..) => match trait_info.principal_def_id() { Some(principal_def_id) if !tcx.trait_is_auto(principal_def_id) => { @@ -231,6 +232,7 @@ impl DeepRejectCtxt { | ty::Slice(..) | ty::RawPtr(..) | ty::Dynamic(..) + | ty::Pat(..) | ty::Ref(..) | ty::Never | ty::Tuple(..) @@ -269,6 +271,10 @@ impl DeepRejectCtxt { } _ => false, }, + ty::Pat(obl_ty, _) => { + // FIXME(pattern_types): take pattern into account + matches!(k, &ty::Pat(impl_ty, _) if self.types_may_unify(obl_ty, impl_ty)) + } ty::Slice(obl_ty) => { matches!(k, &ty::Slice(impl_ty) if self.types_may_unify(obl_ty, impl_ty)) } diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index ca9c762611e..0dc835671d5 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -35,6 +35,15 @@ impl FlagComputation { result } + pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation { + let mut result = FlagComputation::new(); + for c in clauses { + result.add_flags(c.as_predicate().flags()); + result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder()); + } + result + } + fn add_flags(&mut self, flags: TypeFlags) { self.flags = self.flags | flags; } @@ -209,6 +218,20 @@ impl FlagComputation { self.add_const(len); } + &ty::Pat(ty, pat) => { + self.add_ty(ty); + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + if let Some(start) = start { + self.add_const(start) + } + if let Some(end) = end { + self.add_const(end) + } + } + } + } + &ty::Slice(tt) => self.add_ty(tt), &ty::RawPtr(ty, _) => { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index 2630b96869b..e984f543701 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -316,11 +316,11 @@ impl<'tcx> Generics { /// of this item, excluding `Self`. /// /// **This should only be used for diagnostics purposes.** - pub fn own_args_no_defaults( + pub fn own_args_no_defaults<'a>( &'tcx self, tcx: TyCtxt<'tcx>, - args: &'tcx [ty::GenericArg<'tcx>], - ) -> &'tcx [ty::GenericArg<'tcx>] { + args: &'a [ty::GenericArg<'tcx>], + ) -> &'a [ty::GenericArg<'tcx>] { let mut own_params = self.parent_count..self.count(); if self.has_self && self.parent.is_none() { own_params.start = 1; diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs index 129d947697e..ef7a7a99ff7 100644 --- a/compiler/rustc_middle/src/ty/impls_ty.rs +++ b/compiler/rustc_middle/src/ty/impls_ty.rs @@ -11,19 +11,20 @@ use rustc_data_structures::stable_hasher::HashingControls; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey}; use rustc_query_system::ich::StableHashingContext; use std::cell::RefCell; +use std::ptr; -impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T> +impl<'a, 'tcx, H, T> HashStable<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T> where T: HashStable<StableHashingContext<'a>>, { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { thread_local! { - static CACHE: RefCell<FxHashMap<(usize, usize, HashingControls), Fingerprint>> = + static CACHE: RefCell<FxHashMap<(*const (), HashingControls), Fingerprint>> = RefCell::new(Default::default()); } let hash = CACHE.with(|cache| { - let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls()); + let key = (ptr::from_ref(*self).cast::<()>(), hcx.hashing_controls()); if let Some(&hash) = cache.borrow().get(&key) { return hash; } @@ -40,7 +41,7 @@ where } } -impl<'a, 'tcx, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::List<T> +impl<'a, 'tcx, H, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T> where T: HashStable<StableHashingContext<'a>>, { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 4a7720b38f8..f8f59fbeab4 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -520,7 +520,10 @@ impl<'tcx> Instance<'tcx> { // Reify `Trait::method` implementations if KCFI is enabled // FIXME(maurer) only reify it if it is a vtable-safe function _ if tcx.sess.is_sanitizer_kcfi_enabled() - && tcx.associated_item(def_id).trait_item_def_id.is_some() => + && tcx + .opt_associated_item(def_id) + .and_then(|assoc| assoc.trait_item_def_id) + .is_some() => { // 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. diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 66078663098..50e68bfdbe7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -742,6 +742,7 @@ where | ty::FnDef(..) | ty::CoroutineWitness(..) | ty::Foreign(..) + | ty::Pat(_, _) | ty::Dynamic(_, _, ty::Dyn) => { bug!("TyAndLayout::field({:?}): not applicable", this) } diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 336c2dce114..0db541899d2 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -1,7 +1,8 @@ +use super::flags::FlagComputation; +use super::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, TyCtxt, TypeFlags, WithInfcx}; use crate::arena::Arena; use rustc_data_structures::aligned::{align_of, Aligned}; use rustc_serialize::{Encodable, Encoder}; -use rustc_type_ir::{InferCtxtLike, WithInfcx}; use std::alloc::Layout; use std::cmp::Ordering; use std::fmt; @@ -12,6 +13,9 @@ use std::ops::Deref; use std::ptr; use std::slice; +#[cfg(parallel_compiler)] +use rustc_data_structures::sync::DynSync; + /// `List<T>` is a bit like `&[T]`, but with some critical differences. /// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The /// type's correctness relies on this, *but it does not enforce it*. @@ -28,15 +32,33 @@ use std::slice; /// - `T` must be `Copy`. This lets `List<T>` be stored in a dropless arena and /// iterators return a `T` rather than a `&T`. /// - `T` must not be zero-sized. +pub type List<T> = RawList<(), T>; + +/// A generic type that can be used to prepend a [`List`] with some header. +/// +/// The header will be ignored for value-based operations like [`PartialEq`], +/// [`Hash`] and [`Encodable`]. #[repr(C)] -pub struct List<T> { - len: usize, +pub struct RawList<H, T> { + skel: ListSkeleton<H, T>, + opaque: OpaqueListContents, +} +/// A [`RawList`] without the unsized tail. This type is used for layout computation +/// and constructing empty lists. +#[repr(C)] +struct ListSkeleton<H, T> { + header: H, + len: usize, /// Although this claims to be a zero-length array, in practice `len` /// elements are actually present. data: [T; 0], +} - opaque: OpaqueListContents, +impl<T> Default for &List<T> { + fn default() -> Self { + List::empty() + } } extern "C" { @@ -45,35 +67,17 @@ extern "C" { type OpaqueListContents; } -impl<T> List<T> { - /// Returns a reference to the (unique, static) empty list. +impl<H, T> RawList<H, T> { #[inline(always)] - pub fn empty<'a>() -> &'a List<T> { - #[repr(align(64))] - struct MaxAlign; - - assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>()); - - #[repr(C)] - struct InOrder<T, U>(T, U); - - // The empty slice is static and contains a single `0` usize (for the - // length) that is 64-byte aligned, thus featuring the necessary - // trailing padding for elements with up to 64-byte alignment. - static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign); - unsafe { &*(std::ptr::addr_of!(EMPTY_SLICE) as *const List<T>) } - } - pub fn len(&self) -> usize { - self.len + self.skel.len } + #[inline(always)] pub fn as_slice(&self) -> &[T] { self } -} -impl<T: Copy> List<T> { /// Allocates a list from `arena` and copies the contents of `slice` into it. /// /// WARNING: the contents *must be unique*, such that no list with these @@ -84,20 +88,31 @@ impl<T: Copy> List<T> { /// (because the empty list exists statically, and is available via /// `empty()`). #[inline] - pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> { + pub(super) fn from_arena<'tcx>( + arena: &'tcx Arena<'tcx>, + header: H, + slice: &[T], + ) -> &'tcx RawList<H, T> + where + T: Copy, + { assert!(!mem::needs_drop::<T>()); assert!(mem::size_of::<T>() != 0); assert!(!slice.is_empty()); let (layout, _offset) = - Layout::new::<usize>().extend(Layout::for_value::<[T]>(slice)).unwrap(); - let mem = arena.dropless.alloc_raw(layout) as *mut List<T>; + Layout::new::<ListSkeleton<H, T>>().extend(Layout::for_value::<[T]>(slice)).unwrap(); + + let mem = arena.dropless.alloc_raw(layout) as *mut RawList<H, T>; unsafe { + // Write the header + ptr::addr_of_mut!((*mem).skel.header).write(header); + // Write the length - ptr::addr_of_mut!((*mem).len).write(slice.len()); + ptr::addr_of_mut!((*mem).skel.len).write(slice.len()); // Write the elements - ptr::addr_of_mut!((*mem).data) + ptr::addr_of_mut!((*mem).skel.data) .cast::<T>() .copy_from_nonoverlapping(slice.as_ptr(), slice.len()); @@ -110,17 +125,44 @@ impl<T: Copy> List<T> { // // This would be weird, as `self.into_iter` iterates over `T` directly. #[inline(always)] - pub fn iter(&self) -> <&'_ List<T> as IntoIterator>::IntoIter { + pub fn iter(&self) -> <&'_ RawList<H, T> as IntoIterator>::IntoIter + where + T: Copy, + { self.into_iter() } } -impl<T: fmt::Debug> fmt::Debug for List<T> { +macro_rules! impl_list_empty { + ($header_ty:ty, $header_init:expr) => { + impl<T> RawList<$header_ty, T> { + /// Returns a reference to the (per header unique, static) empty list. + #[inline(always)] + pub fn empty<'a>() -> &'a RawList<$header_ty, T> { + #[repr(align(64))] + struct MaxAlign; + + static EMPTY: ListSkeleton<$header_ty, MaxAlign> = + ListSkeleton { header: $header_init, len: 0, data: [] }; + + assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>()); + + // SAFETY: `EMPTY` is sufficiently aligned to be an empty list for all + // types with `align_of(T) <= align_of(MaxAlign)`, which we checked above. + unsafe { &*(std::ptr::addr_of!(EMPTY) as *const RawList<$header_ty, T>) } + } + } + }; +} + +impl_list_empty!((), ()); + +impl<H, T: fmt::Debug> fmt::Debug for RawList<H, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { (**self).fmt(f) } } -impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt<'tcx>> for List<T> { +impl<'tcx, H, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for RawList<H, T> { fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( this: WithInfcx<'_, Infcx, &Self>, f: &mut core::fmt::Formatter<'_>, @@ -129,40 +171,40 @@ impl<'tcx, T: super::DebugWithInfcx<TyCtxt<'tcx>>> super::DebugWithInfcx<TyCtxt< } } -impl<S: Encoder, T: Encodable<S>> Encodable<S> for List<T> { +impl<H, S: Encoder, T: Encodable<S>> Encodable<S> for RawList<H, T> { #[inline] fn encode(&self, s: &mut S) { (**self).encode(s); } } -impl<T: PartialEq> PartialEq for List<T> { +impl<H, T: PartialEq> PartialEq for RawList<H, T> { #[inline] - fn eq(&self, other: &List<T>) -> bool { + fn eq(&self, other: &RawList<H, T>) -> bool { // Pointer equality implies list equality (due to the unique contents // assumption). ptr::eq(self, other) } } -impl<T: Eq> Eq for List<T> {} +impl<H, T: Eq> Eq for RawList<H, T> {} -impl<T> Ord for List<T> +impl<H, T> Ord for RawList<H, T> where T: Ord, { - fn cmp(&self, other: &List<T>) -> Ordering { + fn cmp(&self, other: &RawList<H, T>) -> Ordering { // Pointer equality implies list equality (due to the unique contents // assumption), but the contents must be compared otherwise. if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) } } } -impl<T> PartialOrd for List<T> +impl<H, T> PartialOrd for RawList<H, T> where T: PartialOrd, { - fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> { + fn partial_cmp(&self, other: &RawList<H, T>) -> Option<Ordering> { // Pointer equality implies list equality (due to the unique contents // assumption), but the contents must be compared otherwise. if self == other { @@ -173,16 +215,16 @@ where } } -impl<T> Hash for List<T> { +impl<Hdr, T> Hash for RawList<Hdr, T> { #[inline] fn hash<H: Hasher>(&self, s: &mut H) { // Pointer hashing is sufficient (due to the unique contents // assumption). - (self as *const List<T>).hash(s) + ptr::from_ref(self).hash(s) } } -impl<T> Deref for List<T> { +impl<H, T> Deref for RawList<H, T> { type Target = [T]; #[inline(always)] fn deref(&self) -> &[T] { @@ -190,14 +232,19 @@ impl<T> Deref for List<T> { } } -impl<T> AsRef<[T]> for List<T> { +impl<H, T> AsRef<[T]> for RawList<H, T> { #[inline(always)] fn as_ref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self.data.as_ptr(), self.len) } + let data_ptr = ptr::addr_of!(self.skel.data).cast::<T>(); + // SAFETY: `data_ptr` has the same provenance as `self` and can therefore + // access the `self.skel.len` elements stored at `self.skel.data`. + // Note that we specifically don't reborrow `&self.skel.data`, because that + // would give us a pointer with provenance over 0 bytes. + unsafe { slice::from_raw_parts(data_ptr, self.skel.len) } } } -impl<'a, T: Copy> IntoIterator for &'a List<T> { +impl<'a, H, T: Copy> IntoIterator for &'a RawList<H, T> { type Item = T; type IntoIter = iter::Copied<<&'a [T] as IntoIterator>::IntoIter>; #[inline(always)] @@ -206,27 +253,56 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> { } } -unsafe impl<T: Sync> Sync for List<T> {} +unsafe impl<H: Sync, T: Sync> Sync for RawList<H, T> {} // We need this since `List` uses extern type `OpaqueListContents`. #[cfg(parallel_compiler)] -use rustc_data_structures::sync::DynSync; - -use super::TyCtxt; -#[cfg(parallel_compiler)] -unsafe impl<T: DynSync> DynSync for List<T> {} +unsafe impl<H: DynSync, T: DynSync> DynSync for RawList<H, T> {} // Safety: -// Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail, -// thus aligns of `Equivalent<T>` and `List<T>` must be the same. -unsafe impl<T> Aligned for List<T> { - const ALIGN: ptr::Alignment = { - #[repr(C)] - struct Equivalent<T> { - _len: usize, - _data: [T; 0], - } +// Layouts of `ListSkeleton<H, T>` and `RawList<H, T>` are the same, modulo opaque tail, +// thus aligns of `ListSkeleton<H, T>` and `RawList<H, T>` must be the same. +unsafe impl<H, T> Aligned for RawList<H, T> { + const ALIGN: ptr::Alignment = align_of::<ListSkeleton<H, T>>(); +} - align_of::<Equivalent<T>>() - }; +/// A [`List`] that additionally stores type information inline to speed up +/// [`TypeVisitableExt`](super::TypeVisitableExt) operations. +pub type ListWithCachedTypeInfo<T> = RawList<TypeInfo, T>; + +impl<T> ListWithCachedTypeInfo<T> { + #[inline(always)] + pub fn flags(&self) -> TypeFlags { + self.skel.header.flags + } + + #[inline(always)] + pub fn outer_exclusive_binder(&self) -> DebruijnIndex { + self.skel.header.outer_exclusive_binder + } +} + +impl_list_empty!(TypeInfo, TypeInfo::empty()); + +/// The additional info that is stored in [`ListWithCachedTypeInfo`]. +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct TypeInfo { + flags: TypeFlags, + outer_exclusive_binder: DebruijnIndex, +} + +impl TypeInfo { + const fn empty() -> Self { + Self { flags: TypeFlags::empty(), outer_exclusive_binder: super::INNERMOST } + } +} + +impl From<FlagComputation> for TypeInfo { + fn from(computation: FlagComputation) -> TypeInfo { + TypeInfo { + flags: computation.flags, + outer_exclusive_binder: computation.outer_exclusive_binder, + } + } } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index fb56c71c517..ee4dc9744ac 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -89,8 +89,9 @@ pub use self::context::{ TyCtxt, TyCtxtFeed, }; pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; -pub use self::list::List; +pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::parameterized::ParameterizedOverTcx; +pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate, @@ -130,6 +131,7 @@ pub mod fold; pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; +pub mod pattern; pub mod print; pub mod relate; pub mod trait_def; @@ -1034,6 +1036,18 @@ impl PlaceholderLike for PlaceholderConst { } } +pub type Clauses<'tcx> = &'tcx ListWithCachedTypeInfo<Clause<'tcx>>; + +impl<'tcx> rustc_type_ir::visit::Flags for Clauses<'tcx> { + fn flags(&self) -> TypeFlags { + (**self).flags() + } + + fn outer_exclusive_binder(&self) -> DebruijnIndex { + (**self).outer_exclusive_binder() + } +} + /// When interacting with the type system we must provide information about the /// environment. `ParamEnv` is the type that represents this information. See the /// [dev guide chapter][param_env_guide] for more information. @@ -1053,7 +1067,7 @@ pub struct ParamEnv<'tcx> { /// want `Reveal::All`. /// /// Note: This is packed, use the reveal() method to access it. - packed: CopyTaggedPtr<&'tcx List<Clause<'tcx>>, ParamTag, true>, + packed: CopyTaggedPtr<Clauses<'tcx>, ParamTag, true>, } #[derive(Copy, Clone)] @@ -1112,11 +1126,11 @@ impl<'tcx> ParamEnv<'tcx> { /// [param_env_guide]: https://rustc-dev-guide.rust-lang.org/param_env/param_env_summary.html #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing) + Self::new(ListWithCachedTypeInfo::empty(), Reveal::UserFacing) } #[inline] - pub fn caller_bounds(self) -> &'tcx List<Clause<'tcx>> { + pub fn caller_bounds(self) -> Clauses<'tcx> { self.packed.pointer() } @@ -1134,12 +1148,12 @@ impl<'tcx> ParamEnv<'tcx> { /// or invoke `param_env.with_reveal_all()`. #[inline] pub fn reveal_all() -> Self { - Self::new(List::empty(), Reveal::All) + Self::new(ListWithCachedTypeInfo::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. #[inline] - pub fn new(caller_bounds: &'tcx List<Clause<'tcx>>, reveal: Reveal) -> Self { + pub fn new(caller_bounds: Clauses<'tcx>, reveal: Reveal) -> Self { ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, ParamTag { reveal }) } } @@ -1168,7 +1182,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Returns this same environment but with no caller bounds. #[inline] pub fn without_caller_bounds(self) -> Self { - Self::new(List::empty(), self.reveal()) + Self::new(ListWithCachedTypeInfo::empty(), self.reveal()) } /// Creates a pair of param-env and value for use in queries. diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs new file mode 100644 index 00000000000..8a41ba257ec --- /dev/null +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -0,0 +1,48 @@ +use std::fmt; + +use crate::ty; +use rustc_data_structures::intern::Interned; + +#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)] +#[rustc_pass_by_value] +pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>); + +impl<'tcx> std::ops::Deref for Pattern<'tcx> { + type Target = PatternKind<'tcx>; + + fn deref(&self) -> &Self::Target { + &*self.0 + } +} + +impl<'tcx> fmt::Debug for Pattern<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", **self) + } +} + +impl<'tcx> fmt::Debug for PatternKind<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + PatternKind::Range { start, end, include_end } => { + if let Some(start) = start { + write!(f, "{start}")?; + } + write!(f, "..")?; + if include_end { + write!(f, "=")?; + } + if let Some(end) = end { + write!(f, "{end}")?; + } + Ok(()) + } + } + } +} + +#[derive(Clone, PartialEq, Eq, Hash)] +#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)] +pub enum PatternKind<'tcx> { + Range { start: Option<ty::Const<'tcx>>, end: Option<ty::Const<'tcx>>, include_end: bool }, +} diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index d9aa7f9e5c4..9d0e1123e43 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -259,7 +259,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty::Dynamic(data, ..) => data.principal_def_id(), - ty::Array(subty, _) | ty::Slice(subty) => { + ty::Pat(subty, _) | ty::Array(subty, _) | ty::Slice(subty) => { characteristic_def_id_of_type_cached(subty, visited) } diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 2a898430ce9..20ebd87c3d4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -667,6 +667,9 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { ty::Int(t) => p!(write("{}", t.name_str())), ty::Uint(t) => p!(write("{}", t.name_str())), ty::Float(t) => p!(write("{}", t.name_str())), + ty::Pat(ty, pat) => { + p!("(", print(ty), ") is ", write("{pat:?}")) + } ty::RawPtr(ty, mutbl) => { p!(write( "*{} ", diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index cf7caafcebb..3c1dea1d9f2 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -13,6 +13,8 @@ use rustc_hir::def_id::DefId; use rustc_target::spec::abi; use std::iter; +use super::Pattern; + pub type RelateResult<'tcx, T> = Result<T, TypeError<'tcx>>; pub trait TypeRelation<'tcx>: Sized { @@ -351,6 +353,36 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { } } +impl<'tcx> Relate<'tcx> for Pattern<'tcx> { + #[inline] + fn relate<R: TypeRelation<'tcx>>( + relation: &mut R, + a: Self, + b: Self, + ) -> RelateResult<'tcx, Self> { + match (&*a, &*b) { + ( + &ty::PatternKind::Range { start: start_a, end: end_a, include_end: inc_a }, + &ty::PatternKind::Range { start: start_b, end: end_b, include_end: inc_b }, + ) => { + // FIXME(pattern_types): make equal patterns equal (`0..=` is the same as `..=`). + let mut relate_opt_const = |a, b| match (a, b) { + (None, None) => Ok(None), + (Some(a), Some(b)) => relation.relate(a, b).map(Some), + // FIXME(pattern_types): report a better error + _ => Err(TypeError::Mismatch), + }; + let start = relate_opt_const(start_a, start_b)?; + let end = relate_opt_const(end_a, end_b)?; + if inc_a != inc_b { + todo!() + } + Ok(relation.tcx().mk_pat(ty::PatternKind::Range { start, end, include_end: inc_a })) + } + } + } +} + /// Relates `a` and `b` structurally, calling the relation for all nested values. /// Any semantic equality, e.g. of projections, and inference variables have to be /// handled by the caller. @@ -533,6 +565,12 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_alias(tcx, a_kind, alias_ty)) } + (&ty::Pat(a_ty, a_pat), &ty::Pat(b_ty, b_pat)) => { + let ty = relation.relate(a_ty, b_ty)?; + let pat = relation.relate(a_pat, b_pat)?; + Ok(Ty::new_pat(tcx, ty, pat)) + } + _ => Err(TypeError::Sorts(expected_found(a, b))), } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 0e7010e67d7..90c68e7ddfc 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -20,6 +20,8 @@ use std::fmt::{self, Debug}; use super::print::PrettyPrinter; use super::{GenericArg, GenericArgKind, Region}; +use super::Pattern; + impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { @@ -210,6 +212,22 @@ impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> { } } +impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> { + fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>( + this: WithInfcx<'_, Infcx, &Self>, + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + match &**this.data { + ty::PatternKind::Range { start, end, include_end } => f + .debug_struct("Pattern::Range") + .field("start", start) + .field("end", end) + .field("include_end", include_end) + .finish(), + } + } +} + impl<'tcx> fmt::Debug for ty::consts::Expr<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { WithInfcx::with_no_infcx(self).fmt(f) @@ -541,6 +559,22 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> { } } +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Pattern<'tcx> { + fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( + self, + folder: &mut F, + ) -> Result<Self, F::Error> { + let pat = (*self).clone().try_fold_with(folder)?; + Ok(if pat == *self { self } else { folder.interner().mk_pat(pat) }) + } +} + +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Pattern<'tcx> { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { + (**self).visit_with(visitor) + } +} + impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, @@ -586,6 +620,7 @@ impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for Ty<'tcx> { ty::CoroutineClosure(did, args.try_fold_with(folder)?) } ty::Alias(kind, data) => ty::Alias(kind, data.try_fold_with(folder)?), + ty::Pat(ty, pat) => ty::Pat(ty.try_fold_with(folder)?, pat.try_fold_with(folder)?), ty::Bool | ty::Char @@ -633,6 +668,11 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> { ty::CoroutineClosure(_did, ref args) => args.visit_with(visitor), ty::Alias(_, ref data) => data.visit_with(visitor), + ty::Pat(ty, pat) => { + try_visit!(ty.visit_with(visitor)); + pat.visit_with(visitor) + } + ty::Bool | ty::Char | ty::Str @@ -712,7 +752,19 @@ impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> { } } -impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Clause<'tcx>> { +impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Clauses<'tcx> { + fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { + visitor.visit_clauses(self) + } +} + +impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Clauses<'tcx> { + fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result { + self.as_slice().visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clauses<'tcx> { fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>( self, folder: &mut F, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 2ab63f01e7c..dd73f0f4a35 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1523,6 +1523,11 @@ impl<'tcx> Ty<'tcx> { } #[inline] + pub fn new_pat(tcx: TyCtxt<'tcx>, base: Ty<'tcx>, pat: ty::Pattern<'tcx>) -> Ty<'tcx> { + Ty::new(tcx, Pat(base, pat)) + } + + #[inline] pub fn new_opaque(tcx: TyCtxt<'tcx>, def_id: DefId, args: GenericArgsRef<'tcx>) -> Ty<'tcx> { Ty::new_alias(tcx, ty::Opaque, AliasTy::new(tcx, def_id, args)) } @@ -2226,7 +2231,7 @@ impl<'tcx> Ty<'tcx> { pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> { match self.kind() { Tuple(args) => args, - _ => bug!("tuple_fields called on non-tuple"), + _ => bug!("tuple_fields called on non-tuple: {self:?}"), } } @@ -2278,6 +2283,8 @@ impl<'tcx> Ty<'tcx> { Ty::new_projection(tcx, assoc_items[0], tcx.mk_args(&[self.into()])) } + ty::Pat(ty, _) => ty.discriminant_ty(tcx), + ty::Bool | ty::Char | ty::Int(_) @@ -2359,6 +2366,7 @@ impl<'tcx> Ty<'tcx> { ty::Param(_) | ty::Alias(..) => Err(tail), ty::Infer(ty::TyVar(_)) + | ty::Pat(..) | ty::Bound(..) | ty::Placeholder(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => bug!( @@ -2495,6 +2503,7 @@ impl<'tcx> Ty<'tcx> { | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Array(..) + | ty::Pat(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never @@ -2549,6 +2558,8 @@ impl<'tcx> Ty<'tcx> { field_tys.len() <= 3 && field_tys.iter().all(Self::is_trivially_pure_clone_copy) } + ty::Pat(ty, _) => ty.is_trivially_pure_clone_copy(), + // Sometimes traits aren't implemented for every ABI or arity, // because we can't be generic over everything yet. ty::FnPtr(..) => false, @@ -2630,6 +2641,7 @@ impl<'tcx> Ty<'tcx> { | Foreign(_) | Str | Array(_, _) + | Pat(_, _) | Slice(_) | RawPtr(_, _) | Ref(_, _, _) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index f74bba134ab..e422fb0d020 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -245,6 +245,11 @@ impl<'tcx> TyCtxt<'tcx> { ty::Tuple(_) => break, + ty::Pat(inner, _) => { + f(); + ty = inner; + } + ty::Alias(..) => { let normalized = normalize(ty); if ty == normalized { @@ -1242,7 +1247,7 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) | ty::FnPtr(_) => true, ty::Tuple(fields) => fields.iter().all(Self::is_trivially_freeze), - ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_freeze(), + ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_freeze(), ty::Adt(..) | ty::Bound(..) | ty::Closure(..) @@ -1282,7 +1287,7 @@ impl<'tcx> Ty<'tcx> { | ty::Error(_) | ty::FnPtr(_) => true, ty::Tuple(fields) => fields.iter().all(Self::is_trivially_unpin), - ty::Slice(elem_ty) | ty::Array(elem_ty, _) => elem_ty.is_trivially_unpin(), + ty::Pat(ty, _) | ty::Slice(ty) | ty::Array(ty, _) => ty.is_trivially_unpin(), ty::Adt(..) | ty::Bound(..) | ty::Closure(..) @@ -1398,7 +1403,7 @@ impl<'tcx> Ty<'tcx> { // // Because this function is "shallow", we return `true` for these composites regardless // of the type(s) contained within. - ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true, + ty::Pat(..) | ty::Ref(..) | ty::Array(..) | ty::Slice(_) | ty::Tuple(..) => true, // Raw pointers use bitwise comparison. ty::RawPtr(_, _) | ty::FnPtr(_) => true, @@ -1528,7 +1533,7 @@ pub fn needs_drop_components<'tcx>( ty::Dynamic(..) | ty::Error(_) => Err(AlwaysRequiresDrop), - ty::Slice(ty) => needs_drop_components(tcx, ty), + ty::Pat(ty, _) | ty::Slice(ty) => needs_drop_components(tcx, ty), ty::Array(elem_ty, size) => { match needs_drop_components(tcx, elem_ty) { Ok(v) if v.is_empty() => Ok(v), @@ -1597,7 +1602,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { | ty::CoroutineWitness(..) | ty::Adt(..) => false, - ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty), + ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => is_trivially_const_drop(ty), ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty)), } @@ -1608,16 +1613,18 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool { /// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>(); /// folder.tcx().intern_*(&v) /// ``` -pub fn fold_list<'tcx, F, T>( - list: &'tcx ty::List<T>, +pub fn fold_list<'tcx, F, L, T>( + list: L, folder: &mut F, - intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>, -) -> Result<&'tcx ty::List<T>, F::Error> + intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L, +) -> Result<L, F::Error> where F: FallibleTypeFolder<TyCtxt<'tcx>>, + L: AsRef<[T]>, T: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy, { - let mut iter = list.iter(); + let slice = list.as_ref(); + let mut iter = slice.iter().copied(); // Look for the first element that changed match iter.by_ref().enumerate().find_map(|(i, t)| match t.try_fold_with(folder) { Ok(new_t) if new_t == t => None, @@ -1625,8 +1632,8 @@ where }) { Some((i, Ok(new_t))) => { // An element changed, prepare to intern the resulting list - let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len()); - new_list.extend_from_slice(&list[..i]); + let mut new_list = SmallVec::<[_; 8]>::with_capacity(slice.len()); + new_list.extend_from_slice(&slice[..i]); new_list.push(new_t); for t in iter { new_list.push(t.try_fold_with(folder)?) @@ -1647,8 +1654,8 @@ pub struct AlwaysRequiresDrop; /// with their underlying types. pub fn reveal_opaque_types_in_bounds<'tcx>( tcx: TyCtxt<'tcx>, - val: &'tcx ty::List<ty::Clause<'tcx>>, -) -> &'tcx ty::List<ty::Clause<'tcx>> { + val: ty::Clauses<'tcx>, +) -> ty::Clauses<'tcx> { let mut visitor = OpaqueTypeExpander { seen_opaque_tys: FxHashSet::default(), expanded_cache: FxHashMap::default(), diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs index 9e7bf980237..7069bdcbcb9 100644 --- a/compiler/rustc_middle/src/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -151,6 +151,15 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) | ty::Bound(..) | ty::Foreign(..) => {} + ty::Pat(ty, pat) => { + match *pat { + ty::PatternKind::Range { start, end, include_end: _ } => { + stack.extend(end.map(Into::into)); + stack.extend(start.map(Into::into)); + } + } + stack.push(ty.into()); + } ty::Array(ty, len) => { stack.push(len.into()); stack.push(ty.into()); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index ce39aff69cb..65c53be8ddd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -457,7 +457,7 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } } } - ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { + ty::Pat(..) | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::RawPtr(..) => { // The raw pointers we see here have been "vetted" by valtree construction to be // just integers, so we simply allow them. PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) } diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index e73d945e0bb..d7477309400 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -153,6 +153,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::FnDef(_, _) | ty::FnPtr(_) @@ -193,6 +194,7 @@ impl<'b, 'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> Gatherer<'b, 'a, 'tcx, F> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs index b71c5894ff7..0af88729887 100644 --- a/compiler/rustc_mir_transform/src/check_alignment.rs +++ b/compiler/rustc_mir_transform/src/check_alignment.rs @@ -16,7 +16,7 @@ impl<'tcx> MirPass<'tcx> for CheckAlignment { if sess.target.llvm_target == "i686-pc-windows-msvc" { return false; } - sess.opts.debug_assertions + sess.ub_checks() } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { 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 de43f9faff9..ccb229616e8 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -58,16 +58,24 @@ //! borrowing from the outer closure, and we simply peel off a `deref` projection //! from them. This second body is stored alongside the first body, and optimized //! with it in lockstep. When we need to resolve a body for `FnOnce` or `AsyncFnOnce`, -//! we use this "by move" body instead. - -use itertools::Itertools; +//! we use this "by-move" body instead. +//! +//! ## How does this work? +//! +//! This pass essentially remaps the body of the (child) closure of the coroutine-closure +//! to take the set of upvars of the parent closure by value. This at least requires +//! changing a by-ref upvar to be by-value in the case that the outer coroutine-closure +//! captures something by value; however, it may also require renumbering field indices +//! in case precise captures (edition 2021 closure capture rules) caused the inner coroutine +//! to split one field capture into two. -use rustc_data_structures::unord::UnordSet; +use rustc_data_structures::unord::UnordMap; use rustc_hir as hir; +use rustc_middle::hir::place::{PlaceBase, 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_target::abi::FieldIdx; +use rustc_target::abi::{FieldIdx, VariantIdx}; pub struct ByMoveBody; @@ -116,32 +124,90 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { .tuple_fields() .len(); - let mut by_ref_fields = UnordSet::default(); - for (idx, (coroutine_capture, parent_capture)) in tcx + let mut field_remapping = UnordMap::default(); + + let mut child_captures = tcx .closure_captures(coroutine_def_id) .iter() + .copied() // By construction we capture all the args first. .skip(num_args) - .zip_eq(tcx.closure_captures(parent_def_id)) .enumerate() + .peekable(); + + // One parent capture may correspond to several child captures if we end up + // refining the set of captures via edition-2021 precise captures. We want to + // match up any number of child captures with one parent capture, so we keep + // peeking off this `Peekable` until the child doesn't match anymore. + for (parent_field_idx, parent_capture) in + tcx.closure_captures(parent_def_id).iter().copied().enumerate() { - // This upvar is captured by-move from the parent closure, but by-ref - // from the inner async block. That means that it's being borrowed from - // the outer closure body -- we need to change the coroutine to take the - // upvar by value. - if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() { - assert_ne!( - coroutine_kind, - ty::ClosureKind::FnOnce, - "`FnOnce` coroutine-closures return coroutines that capture from \ - their body; it will always result in a borrowck error!" + // Make sure we use every field at least once, b/c why are we capturing something + // if it's not used in the inner coroutine. + let mut field_used_at_least_once = false; + + // A parent matches a child if they share the same prefix of projections. + // The child may have more, if it is capturing sub-fields out of + // something that is captured by-move in the parent closure. + while child_captures.peek().map_or(false, |(_, child_capture)| { + child_prefix_matches_parent_projections(parent_capture, child_capture) + }) { + let (child_field_idx, child_capture) = child_captures.next().unwrap(); + + // Store this set of additional projections (fields and derefs). + // We need to re-apply them later. + let child_precise_captures = + &child_capture.place.projections[parent_capture.place.projections.len()..]; + + // If the parent captures by-move, and the child captures by-ref, then we + // need to peel an additional `deref` off of the body of the child. + let needs_deref = child_capture.is_by_ref() && !parent_capture.is_by_ref(); + if needs_deref { + assert_ne!( + coroutine_kind, + ty::ClosureKind::FnOnce, + "`FnOnce` coroutine-closures return coroutines that capture from \ + their body; it will always result in a borrowck error!" + ); + } + + // Finally, store the type of the parent's captured place. We need + // this when building the field projection in the MIR body later on. + let mut parent_capture_ty = parent_capture.place.ty(); + parent_capture_ty = match parent_capture.info.capture_kind { + ty::UpvarCapture::ByValue => parent_capture_ty, + ty::UpvarCapture::ByRef(kind) => Ty::new_ref( + tcx, + tcx.lifetimes.re_erased, + parent_capture_ty, + kind.to_mutbl_lossy(), + ), + }; + + field_remapping.insert( + FieldIdx::from_usize(child_field_idx + num_args), + ( + FieldIdx::from_usize(parent_field_idx + num_args), + parent_capture_ty, + needs_deref, + child_precise_captures, + ), ); - by_ref_fields.insert(FieldIdx::from_usize(num_args + idx)); + + field_used_at_least_once = true; } - // Make sure we're actually talking about the same capture. - // FIXME(async_closures): We could look at the `hir::Upvar` instead? - assert_eq!(coroutine_capture.place.ty(), parent_capture.place.ty()); + // Make sure the field was used at least once. + assert!( + field_used_at_least_once, + "we captured {parent_capture:#?} but it was not used in the child coroutine?" + ); + } + assert_eq!(child_captures.next(), None, "leftover child captures?"); + + if coroutine_kind == ty::ClosureKind::FnOnce { + assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len()); + return; } let by_move_coroutine_ty = tcx @@ -157,8 +223,9 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { ); let mut by_move_body = body.clone(); - MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body); + 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 { coroutine_def_id: coroutine_def_id.to_def_id(), }); @@ -166,9 +233,26 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { } } +fn child_prefix_matches_parent_projections( + parent_capture: &ty::CapturedPlace<'_>, + child_capture: &ty::CapturedPlace<'_>, +) -> bool { + let PlaceBase::Upvar(parent_base) = parent_capture.place.base else { + bug!("expected capture to be an upvar"); + }; + let PlaceBase::Upvar(child_base) = child_capture.place.base else { + bug!("expected capture to be an upvar"); + }; + + assert!(child_capture.place.projections.len() >= parent_capture.place.projections.len()); + parent_base.var_path.hir_id == child_base.var_path.hir_id + && std::iter::zip(&child_capture.place.projections, &parent_capture.place.projections) + .all(|(child, parent)| child.kind == parent.kind) +} + struct MakeByMoveBody<'tcx> { tcx: TyCtxt<'tcx>, - by_ref_fields: UnordSet<FieldIdx>, + field_remapping: UnordMap<FieldIdx, (FieldIdx, Ty<'tcx>, bool, &'tcx [Projection<'tcx>])>, by_move_coroutine_ty: Ty<'tcx>, } @@ -183,24 +267,57 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { context: mir::visit::PlaceContext, location: mir::Location, ) { + // Initializing an upvar local always starts with `CAPTURE_STRUCT_LOCAL` and a + // field projection. If this is in `field_remapping`, then it must not be an + // arg from calling the closure, but instead an upvar. if place.local == ty::CAPTURE_STRUCT_LOCAL - && let Some((&mir::ProjectionElem::Field(idx, ty), projection)) = + && let Some((&mir::ProjectionElem::Field(idx, _), projection)) = place.projection.split_first() - && self.by_ref_fields.contains(&idx) + && let Some(&(remapped_idx, remapped_ty, needs_deref, bridging_projections)) = + self.field_remapping.get(&idx) { - let (begin, end) = projection.split_first().unwrap(); - // FIXME(async_closures): I'm actually a bit surprised to see that we always - // initially deref the by-ref upvars. If this is not actually true, then we - // will at least get an ICE that explains why this isn't true :^) - assert_eq!(*begin, mir::ProjectionElem::Deref); - // Peel one ref off of the ty. - let peeled_ty = ty.builtin_deref(true).unwrap().ty; + // As noted before, if the parent closure captures a field by value, and + // the child captures a field by ref, then for the by-move body we're + // generating, we also are taking that field by value. Peel off a deref, + // since a layer of ref'ing has now become redundant. + let final_projections = if needs_deref { + let Some((mir::ProjectionElem::Deref, projection)) = projection.split_first() + else { + bug!( + "There should be at least a single deref for an upvar local initialization, found {projection:#?}" + ); + }; + // There may be more derefs, since we may also implicitly reborrow + // a captured mut pointer. + projection + } else { + projection + }; + + // These projections are applied in order to "bridge" the local that we are + // currently transforming *from* the old upvar that the by-ref coroutine used + // to capture *to* the upvar of the parent coroutine-closure. For example, if + // the parent captures `&s` but the child captures `&(s.field)`, then we will + // apply a field projection. + let bridging_projections = bridging_projections.iter().map(|elem| match elem.kind { + ProjectionKind::Deref => mir::ProjectionElem::Deref, + ProjectionKind::Field(idx, VariantIdx::ZERO) => { + mir::ProjectionElem::Field(idx, elem.ty) + } + _ => unreachable!("precise captures only through fields and derefs"), + }); + + // We start out with an adjusted field index (and ty), representing the + // upvar that we get from our parent closure. We apply any of the additional + // projections to make sure that to the rest of the body of the closure, the + // place looks the same, and then apply that final deref if necessary. *place = mir::Place { local: place.local, projection: self.tcx.mk_place_elems_from_iter( - [mir::ProjectionElem::Field(idx, peeled_ty)] + [mir::ProjectionElem::Field(remapped_idx, remapped_ty)] .into_iter() - .chain(end.iter().copied()), + .chain(bridging_projections) + .chain(final_projections.iter().copied()), ), }; } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 3e9c1459f1c..d0f6ec8f21f 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -684,6 +684,7 @@ fn try_write_constant<'tcx>( // Unsupported for now. ty::Array(_, _) + | ty::Pat(_, _) // Do not attempt to support indirection in constants. | ty::Ref(..) | ty::RawPtr(..) | ty::FnPtr(..) | ty::Str | ty::Slice(_) diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index 0d600f0f937..9edb8bcee6e 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -1,6 +1,6 @@ use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{Ty, TyCtxt}; use std::fmt::Debug; use super::simplify::simplify_cfg; @@ -11,6 +11,7 @@ use super::simplify::simplify_cfg; /// let y: Option<()>; /// match (x,y) { /// (Some(_), Some(_)) => {0}, +/// (None, None) => {2}, /// _ => {1} /// } /// ``` @@ -23,10 +24,10 @@ use super::simplify::simplify_cfg; /// if discriminant_x == discriminant_y { /// match x { /// Some(_) => 0, -/// _ => 1, // <---- -/// } // | Actually the same bb -/// } else { // | -/// 1 // <-------------- +/// None => 2, +/// } +/// } else { +/// 1 /// } /// ``` /// @@ -47,18 +48,18 @@ use super::simplify::simplify_cfg; /// | | | /// ================= | | | /// | BBU | <-| | | ============================ -/// |---------------| | \-------> | BBD | -/// |---------------| | | |--------------------------| -/// | unreachable | | | | _dl = discriminant(P) | -/// ================= | | |--------------------------| -/// | | | switchInt(_dl) | -/// ================= | | | d | ---> BBD.2 +/// |---------------| \-------> | BBD | +/// |---------------| | |--------------------------| +/// | unreachable | | | _dl = discriminant(P) | +/// ================= | |--------------------------| +/// | | switchInt(_dl) | +/// ================= | | d | ---> BBD.2 /// | BB9 | <--------------- | otherwise | /// |---------------| ============================ /// | ... | /// ================= /// ``` -/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU` or to `BB9`. In the +/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU`. In the /// code: /// - `BB1` is `parent` and `BBC, BBD` are children /// - `P` is `child_place` @@ -78,7 +79,7 @@ use super::simplify::simplify_cfg; /// |---------------------| | | switchInt(Q) | /// | switchInt(_t) | | | c | ---> BBC.2 /// | false | --------/ | d | ---> BBD.2 -/// | otherwise | ---------------- | otherwise | +/// | otherwise | /--------- | otherwise | /// ======================= | ============================ /// | /// ================= | @@ -87,16 +88,11 @@ use super::simplify::simplify_cfg; /// | ... | /// ================= /// ``` -/// -/// This is only correct for some `P`, since `P` is now computed outside the original `switchInt`. -/// The filter on which `P` are allowed (together with discussion of its correctness) is found in -/// `may_hoist`. pub struct EarlyOtherwiseBranch; impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // unsound: https://github.com/rust-lang/rust/issues/95162 - sess.mir_opt_level() >= 3 && sess.opts.unstable_opts.unsound_mir_opts + sess.mir_opt_level() >= 2 } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { @@ -172,7 +168,8 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { }; (value, targets.target_for_value(value)) }); - let eq_targets = SwitchTargets::new(eq_new_targets, opt_data.destination); + // The otherwise either is the same target branch or an unreachable. + let eq_targets = SwitchTargets::new(eq_new_targets, parent_targets.otherwise()); // Create `bbEq` in example above let eq_switch = BasicBlockData::new(Some(Terminator { @@ -217,85 +214,6 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { } } -/// Returns true if computing the discriminant of `place` may be hoisted out of the branch -fn may_hoist<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>) -> bool { - // FIXME(JakobDegen): This is unsound. Someone could write code like this: - // ```rust - // let Q = val; - // if discriminant(P) == otherwise { - // let ptr = &mut Q as *mut _ as *mut u8; - // unsafe { *ptr = 10; } // Any invalid value for the type - // } - // - // match P { - // A => match Q { - // A => { - // // code - // } - // _ => { - // // don't use Q - // } - // } - // _ => { - // // don't use Q - // } - // }; - // ``` - // - // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an - // invalid value, which is UB. - // - // In order to fix this, we would either need to show that the discriminant computation of - // `place` is computed in all branches, including the `otherwise` branch, or we would need - // another analysis pass to determine that the place is fully initialized. It might even be best - // to have the hoisting be performed in a different pass and just do the CFG changing in this - // pass. - for (place, proj) in place.iter_projections() { - match proj { - // Dereferencing in the computation of `place` might cause issues from one of two - // categories. First, the referent might be invalid. We protect against this by - // dereferencing references only (not pointers). Second, the use of a reference may - // invalidate other references that are used later (for aliasing reasons). Consider - // where such an invalidated reference may appear: - // - In `Q`: Not possible since `Q` is used as the operand of a `SwitchInt` and so - // cannot contain referenced data. - // - In `BBU`: Not possible since that block contains only the `unreachable` terminator - // - In `BBC.2, BBD.2`: Not possible, since `discriminant(P)` was computed prior to - // reaching that block in the input to our transformation, and so any data - // invalidated by that computation could not have been used there. - // - In `BB9`: Not possible since control flow might have reached `BB9` via the - // `otherwise` branch in `BBC, BBD` in the input to our transformation, which would - // have invalidated the data when computing `discriminant(P)` - // So dereferencing here is correct. - ProjectionElem::Deref => match place.ty(body.local_decls(), tcx).ty.kind() { - ty::Ref(..) => {} - _ => return false, - }, - // Field projections are always valid - ProjectionElem::Field(..) => {} - // We cannot allow - // downcasts either, since the correctness of the downcast may depend on the parent - // branch being taken. An easy example of this is - // ``` - // Q = discriminant(_3) - // P = (_3 as Variant) - // ``` - // However, checking if the child and parent place are the same and only erroring then - // is not sufficient either, since the `discriminant(_3) == 1` (or whatever) check may - // be replaced by another optimization pass with any other condition that can be proven - // equivalent. - ProjectionElem::Downcast(..) => { - return false; - } - // We cannot allow indexing since the index may be out of bounds. - _ => { - return false; - } - } - } - true -} - #[derive(Debug)] struct OptimizationData<'tcx> { destination: BasicBlock, @@ -315,18 +233,40 @@ fn evaluate_candidate<'tcx>( return None; }; let parent_ty = parent_discr.ty(body.local_decls(), tcx); - let parent_dest = { - let poss = targets.otherwise(); - // If the fallthrough on the parent is trivially unreachable, we can let the - // children choose the destination - if bbs[poss].statements.len() == 0 - && bbs[poss].terminator().kind == TerminatorKind::Unreachable - { - None - } else { - Some(poss) - } - }; + if !bbs[targets.otherwise()].is_empty_unreachable() { + // Someone could write code like this: + // ```rust + // let Q = val; + // if discriminant(P) == otherwise { + // let ptr = &mut Q as *mut _ as *mut u8; + // // It may be difficult for us to effectively determine whether values are valid. + // // Invalid values can come from all sorts of corners. + // unsafe { *ptr = 10; } + // } + // + // match P { + // A => match Q { + // A => { + // // code + // } + // _ => { + // // don't use Q + // } + // } + // _ => { + // // don't use Q + // } + // }; + // ``` + // + // Hoisting the `discriminant(Q)` out of the `A` arm causes us to compute the discriminant of an + // invalid value, which is UB. + // In order to fix this, **we would either need to show that the discriminant computation of + // `place` is computed in all branches**. + // FIXME(#95162) For the moment, we adopt a conservative approach and + // consider only the `otherwise` branch has no statements and an unreachable terminator. + return None; + } let (_, child) = targets.iter().next()?; let child_terminator = &bbs[child].terminator(); let TerminatorKind::SwitchInt { targets: child_targets, discr: child_discr } = @@ -344,13 +284,7 @@ fn evaluate_candidate<'tcx>( let (_, Rvalue::Discriminant(child_place)) = &**boxed else { return None; }; - let destination = parent_dest.unwrap_or(child_targets.otherwise()); - - // Verify that the optimization is legal in general - // We can hoist evaluating the child discriminant out of the branch - if !may_hoist(tcx, body, *child_place) { - return None; - } + let destination = child_targets.otherwise(); // Verify that the optimization is legal for each branch for (value, child) in targets.iter() { @@ -411,5 +345,5 @@ fn verify_candidate_branch<'tcx>( if let Some(_) = iter.next() { return false; } - return true; + true } diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 1b38eeccfad..ff786d44d6a 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -149,7 +149,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { fn simplify_ub_check(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::NullaryOp(NullOp::UbChecks, _) = *rvalue { - let const_ = Const::from_bool(self.tcx, self.tcx.sess.opts.debug_assertions); + let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); let constant = ConstOperand { span: source_info.span, const_, user_ty: None }; *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); } diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs index 6d4332793af..4d9a198eeb2 100644 --- a/compiler/rustc_mir_transform/src/match_branches.rs +++ b/compiler/rustc_mir_transform/src/match_branches.rs @@ -1,11 +1,125 @@ +use rustc_index::IndexSlice; +use rustc_middle::mir::patch::MirPatch; use rustc_middle::mir::*; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt}; +use rustc_target::abi::Size; use std::iter; use super::simplify::simplify_cfg; pub struct MatchBranchSimplification; +impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { + fn is_enabled(&self, sess: &rustc_session::Session) -> bool { + sess.mir_opt_level() >= 1 + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let def_id = body.source.def_id(); + let param_env = tcx.param_env_reveal_all_normalized(def_id); + + let mut should_cleanup = false; + for i in 0..body.basic_blocks.len() { + let bbs = &*body.basic_blocks; + let bb_idx = BasicBlock::from_usize(i); + if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {def_id:?} ")) { + continue; + } + + match bbs[bb_idx].terminator().kind { + TerminatorKind::SwitchInt { + discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)), + ref targets, + .. + // We require that the possible target blocks don't contain this block. + } if !targets.all_targets().contains(&bb_idx) => {} + // Only optimize switch int statements + _ => continue, + }; + + if SimplifyToIf.simplify(tcx, body, bb_idx, param_env).is_some() { + should_cleanup = true; + continue; + } + if SimplifyToExp::default().simplify(tcx, body, bb_idx, param_env).is_some() { + should_cleanup = true; + continue; + } + } + + if should_cleanup { + simplify_cfg(body); + } + } +} + +trait SimplifyMatch<'tcx> { + /// Simplifies a match statement, returning true if the simplification succeeds, false otherwise. + /// Generic code is written here, and we generally don't need a custom implementation. + fn simplify( + &mut self, + tcx: TyCtxt<'tcx>, + body: &mut Body<'tcx>, + switch_bb_idx: BasicBlock, + param_env: ParamEnv<'tcx>, + ) -> Option<()> { + let bbs = &body.basic_blocks; + let (discr, targets) = match bbs[switch_bb_idx].terminator().kind { + TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets), + _ => unreachable!(), + }; + + let discr_ty = discr.ty(body.local_decls(), tcx); + self.can_simplify(tcx, targets, param_env, bbs, discr_ty)?; + + let mut patch = MirPatch::new(body); + + // Take ownership of items now that we know we can optimize. + let discr = discr.clone(); + + // Introduce a temporary for the discriminant value. + let source_info = bbs[switch_bb_idx].terminator().source_info; + let discr_local = patch.new_temp(discr_ty, source_info.span); + + let (_, first) = targets.iter().next().unwrap(); + let statement_index = bbs[switch_bb_idx].statements.len(); + let parent_end = Location { block: switch_bb_idx, statement_index }; + patch.add_statement(parent_end, StatementKind::StorageLive(discr_local)); + patch.add_assign(parent_end, Place::from(discr_local), Rvalue::Use(discr)); + self.new_stmts(tcx, targets, param_env, &mut patch, parent_end, bbs, discr_local, discr_ty); + patch.add_statement(parent_end, StatementKind::StorageDead(discr_local)); + patch.patch_terminator(switch_bb_idx, bbs[first].terminator().kind.clone()); + patch.apply(body); + Some(()) + } + + /// Check that the BBs to be simplified satisfies all distinct and + /// that the terminator are the same. + /// There are also conditions for different ways of simplification. + fn can_simplify( + &mut self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_ty: Ty<'tcx>, + ) -> Option<()>; + + fn new_stmts( + &self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + patch: &mut MirPatch<'tcx>, + parent_end: Location, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_local: Local, + discr_ty: Ty<'tcx>, + ); +} + +struct SimplifyToIf; + /// If a source block is found that switches between two blocks that are exactly /// the same modulo const bool assignments (e.g., one assigns true another false /// to the same place), merge a target block statements into the source block, @@ -37,144 +151,350 @@ pub struct MatchBranchSimplification; /// goto -> bb3; /// } /// ``` +impl<'tcx> SimplifyMatch<'tcx> for SimplifyToIf { + fn can_simplify( + &mut self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + _discr_ty: Ty<'tcx>, + ) -> Option<()> { + if targets.iter().len() != 1 { + return None; + } + // We require that the possible target blocks all be distinct. + let (_, first) = targets.iter().next().unwrap(); + let second = targets.otherwise(); + if first == second { + return None; + } + // Check that destinations are identical, and if not, then don't optimize this block + if bbs[first].terminator().kind != bbs[second].terminator().kind { + return None; + } -impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { - fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - sess.mir_opt_level() >= 1 - } + // Check that blocks are assignments of consts to the same place or same statement, + // and match up 1-1, if not don't optimize this block. + let first_stmts = &bbs[first].statements; + let second_stmts = &bbs[second].statements; + if first_stmts.len() != second_stmts.len() { + return None; + } + for (f, s) in iter::zip(first_stmts, second_stmts) { + match (&f.kind, &s.kind) { + // If two statements are exactly the same, we can optimize. + (f_s, s_s) if f_s == s_s => {} - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - let def_id = body.source.def_id(); - let param_env = tcx.param_env_reveal_all_normalized(def_id); + // If two statements are const bool assignments to the same place, we can optimize. + ( + StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s + && f_c.const_.ty().is_bool() + && s_c.const_.ty().is_bool() + && f_c.const_.try_eval_bool(tcx, param_env).is_some() + && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {} - let bbs = body.basic_blocks.as_mut(); - let mut should_cleanup = false; - 'outer: for bb_idx in bbs.indices() { - if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {def_id:?} ")) { - continue; + // Otherwise we cannot optimize. Try another block. + _ => return None, } + } + Some(()) + } - let (discr, val, first, second) = match bbs[bb_idx].terminator().kind { - TerminatorKind::SwitchInt { - discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)), - ref targets, - .. - } if targets.iter().len() == 1 => { - let (value, target) = targets.iter().next().unwrap(); - // We require that this block and the two possible target blocks all be - // distinct. - if target == targets.otherwise() - || bb_idx == target - || bb_idx == targets.otherwise() - { - continue; + fn new_stmts( + &self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + patch: &mut MirPatch<'tcx>, + parent_end: Location, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_local: Local, + discr_ty: Ty<'tcx>, + ) { + let (val, first) = targets.iter().next().unwrap(); + let second = targets.otherwise(); + // We already checked that first and second are different blocks, + // and bb_idx has a different terminator from both of them. + let first = &bbs[first]; + let second = &bbs[second]; + for (f, s) in iter::zip(&first.statements, &second.statements) { + match (&f.kind, &s.kind) { + (f_s, s_s) if f_s == s_s => { + patch.add_statement(parent_end, f.kind.clone()); + } + + ( + StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), + StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), + ) => { + // From earlier loop we know that we are dealing with bool constants only: + let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap(); + let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap(); + if f_b == s_b { + // Same value in both blocks. Use statement as is. + patch.add_statement(parent_end, f.kind.clone()); + } else { + // Different value between blocks. Make value conditional on switch condition. + let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; + let const_cmp = Operand::const_from_scalar( + tcx, + discr_ty, + rustc_const_eval::interpret::Scalar::from_uint(val, size), + rustc_span::DUMMY_SP, + ); + let op = if f_b { BinOp::Eq } else { BinOp::Ne }; + let rhs = Rvalue::BinaryOp( + op, + Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)), + ); + patch.add_assign(parent_end, *lhs, rhs); } - (discr, value, target, targets.otherwise()) } - // Only optimize switch int statements - _ => continue, - }; - // Check that destinations are identical, and if not, then don't optimize this block - if bbs[first].terminator().kind != bbs[second].terminator().kind { - continue; + _ => unreachable!(), } + } + } +} - // Check that blocks are assignments of consts to the same place or same statement, - // and match up 1-1, if not don't optimize this block. - let first_stmts = &bbs[first].statements; - let scnd_stmts = &bbs[second].statements; - if first_stmts.len() != scnd_stmts.len() { - continue; - } - for (f, s) in iter::zip(first_stmts, scnd_stmts) { - match (&f.kind, &s.kind) { - // If two statements are exactly the same, we can optimize. - (f_s, s_s) if f_s == s_s => {} +#[derive(Default)] +struct SimplifyToExp { + transfrom_types: Vec<TransfromType>, +} - // If two statements are const bool assignments to the same place, we can optimize. - ( - StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), - StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), - ) if lhs_f == lhs_s - && f_c.const_.ty().is_bool() - && s_c.const_.ty().is_bool() - && f_c.const_.try_eval_bool(tcx, param_env).is_some() - && s_c.const_.try_eval_bool(tcx, param_env).is_some() => {} +#[derive(Clone, Copy)] +enum CompareType<'tcx, 'a> { + /// Identical statements. + Same(&'a StatementKind<'tcx>), + /// Assignment statements have the same value. + Eq(&'a Place<'tcx>, Ty<'tcx>, ScalarInt), + /// Enum variant comparison type. + Discr { place: &'a Place<'tcx>, ty: Ty<'tcx>, is_signed: bool }, +} - // Otherwise we cannot optimize. Try another block. - _ => continue 'outer, - } - } - // Take ownership of items now that we know we can optimize. - let discr = discr.clone(); - let discr_ty = discr.ty(&body.local_decls, tcx); +enum TransfromType { + Same, + Eq, + Discr, +} + +impl From<CompareType<'_, '_>> for TransfromType { + fn from(compare_type: CompareType<'_, '_>) -> Self { + match compare_type { + CompareType::Same(_) => TransfromType::Same, + CompareType::Eq(_, _, _) => TransfromType::Eq, + CompareType::Discr { .. } => TransfromType::Discr, + } + } +} + +/// If we find that the value of match is the same as the assignment, +/// merge a target block statements into the source block, +/// using cast to transform different integer types. +/// +/// For example: +/// +/// ```ignore (MIR) +/// bb0: { +/// switchInt(_1) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1]; +/// } +/// +/// bb1: { +/// unreachable; +/// } +/// +/// bb2: { +/// _0 = const 1_i16; +/// goto -> bb5; +/// } +/// +/// bb3: { +/// _0 = const 2_i16; +/// goto -> bb5; +/// } +/// +/// bb4: { +/// _0 = const 3_i16; +/// goto -> bb5; +/// } +/// ``` +/// +/// into: +/// +/// ```ignore (MIR) +/// bb0: { +/// _0 = _3 as i16 (IntToInt); +/// goto -> bb5; +/// } +/// ``` +impl<'tcx> SimplifyMatch<'tcx> for SimplifyToExp { + fn can_simplify( + &mut self, + tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + param_env: ParamEnv<'tcx>, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_ty: Ty<'tcx>, + ) -> Option<()> { + if targets.iter().len() < 2 || targets.iter().len() > 64 { + return None; + } + // We require that the possible target blocks all be distinct. + if !targets.is_distinct() { + return None; + } + if !bbs[targets.otherwise()].is_empty_unreachable() { + return None; + } + let mut target_iter = targets.iter(); + let (first_val, first_target) = target_iter.next().unwrap(); + let first_terminator_kind = &bbs[first_target].terminator().kind; + // Check that destinations are identical, and if not, then don't optimize this block + if !targets + .iter() + .all(|(_, other_target)| first_terminator_kind == &bbs[other_target].terminator().kind) + { + return None; + } - // Introduce a temporary for the discriminant value. - let source_info = bbs[bb_idx].terminator().source_info; - let discr_local = body.local_decls.push(LocalDecl::new(discr_ty, source_info.span)); + let discr_size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; + let first_stmts = &bbs[first_target].statements; + let (second_val, second_target) = target_iter.next().unwrap(); + let second_stmts = &bbs[second_target].statements; + if first_stmts.len() != second_stmts.len() { + return None; + } - // We already checked that first and second are different blocks, - // and bb_idx has a different terminator from both of them. - let (from, first, second) = bbs.pick3_mut(bb_idx, first, second); + fn int_equal(l: ScalarInt, r: impl Into<u128>, size: Size) -> bool { + l.try_to_int(l.size()).unwrap() + == ScalarInt::try_from_uint(r, size).unwrap().try_to_int(size).unwrap() + } - let new_stmts = iter::zip(&first.statements, &second.statements).map(|(f, s)| { - match (&f.kind, &s.kind) { - (f_s, s_s) if f_s == s_s => (*f).clone(), + // We first compare the two branches, and then the other branches need to fulfill the same conditions. + let mut compare_types = Vec::new(); + for (f, s) in iter::zip(first_stmts, second_stmts) { + let compare_type = match (&f.kind, &s.kind) { + // If two statements are exactly the same, we can optimize. + (f_s, s_s) if f_s == s_s => CompareType::Same(f_s), - ( - StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), - StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))), - ) => { - // From earlier loop we know that we are dealing with bool constants only: - let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap(); - let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap(); - if f_b == s_b { - // Same value in both blocks. Use statement as is. - (*f).clone() - } else { - // Different value between blocks. Make value conditional on switch condition. - let size = tcx.layout_of(param_env.and(discr_ty)).unwrap().size; - let const_cmp = Operand::const_from_scalar( - tcx, - discr_ty, - rustc_const_eval::interpret::Scalar::from_uint(val, size), - rustc_span::DUMMY_SP, - ); - let op = if f_b { BinOp::Eq } else { BinOp::Ne }; - let rhs = Rvalue::BinaryOp( - op, - Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)), - ); - Statement { - source_info: f.source_info, - kind: StatementKind::Assign(Box::new((*lhs, rhs))), + // If two statements are assignments with the match values to the same place, we can optimize. + ( + StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))), + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s + && f_c.const_.ty() == s_c.const_.ty() + && f_c.const_.ty().is_integral() => + { + match ( + f_c.const_.try_eval_scalar_int(tcx, param_env), + s_c.const_.try_eval_scalar_int(tcx, param_env), + ) { + (Some(f), Some(s)) if f == s => CompareType::Eq(lhs_f, f_c.const_.ty(), f), + // Enum variants can also be simplified to an assignment statement if their values are equal. + // We need to consider both unsigned and signed scenarios here. + (Some(f), Some(s)) + if ((f_c.const_.ty().is_signed() || discr_ty.is_signed()) + && int_equal(f, first_val, discr_size) + && int_equal(s, second_val, discr_size)) + || (Some(f) == ScalarInt::try_from_uint(first_val, f.size()) + && Some(s) + == ScalarInt::try_from_uint(second_val, s.size())) => + { + CompareType::Discr { + place: lhs_f, + ty: f_c.const_.ty(), + is_signed: f_c.const_.ty().is_signed() || discr_ty.is_signed(), } } + _ => { + return None; + } } + } + + // Otherwise we cannot optimize. Try another block. + _ => return None, + }; + compare_types.push(compare_type); + } - _ => unreachable!(), + // All remaining BBs need to fulfill the same pattern as the two BBs from the previous step. + for (other_val, other_target) in target_iter { + let other_stmts = &bbs[other_target].statements; + if compare_types.len() != other_stmts.len() { + return None; + } + for (f, s) in iter::zip(&compare_types, other_stmts) { + match (*f, &s.kind) { + (CompareType::Same(f_s), s_s) if f_s == s_s => {} + ( + CompareType::Eq(lhs_f, f_ty, val), + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s + && s_c.const_.ty() == f_ty + && s_c.const_.try_eval_scalar_int(tcx, param_env) == Some(val) => {} + ( + CompareType::Discr { place: lhs_f, ty: f_ty, is_signed }, + StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))), + ) if lhs_f == lhs_s && s_c.const_.ty() == f_ty => { + let Some(f) = s_c.const_.try_eval_scalar_int(tcx, param_env) else { + return None; + }; + if is_signed + && s_c.const_.ty().is_signed() + && int_equal(f, other_val, discr_size) + { + continue; + } + if Some(f) == ScalarInt::try_from_uint(other_val, f.size()) { + continue; + } + return None; + } + _ => return None, } - }); - - from.statements - .push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) }); - from.statements.push(Statement { - source_info, - kind: StatementKind::Assign(Box::new(( - Place::from(discr_local), - Rvalue::Use(discr), - ))), - }); - from.statements.extend(new_stmts); - from.statements - .push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) }); - from.terminator_mut().kind = first.terminator().kind.clone(); - should_cleanup = true; + } } + self.transfrom_types = compare_types.into_iter().map(|c| c.into()).collect(); + Some(()) + } - if should_cleanup { - simplify_cfg(body); + fn new_stmts( + &self, + _tcx: TyCtxt<'tcx>, + targets: &SwitchTargets, + _param_env: ParamEnv<'tcx>, + patch: &mut MirPatch<'tcx>, + parent_end: Location, + bbs: &IndexSlice<BasicBlock, BasicBlockData<'tcx>>, + discr_local: Local, + discr_ty: Ty<'tcx>, + ) { + let (_, first) = targets.iter().next().unwrap(); + let first = &bbs[first]; + + for (t, s) in iter::zip(&self.transfrom_types, &first.statements) { + match (t, &s.kind) { + (TransfromType::Same, _) | (TransfromType::Eq, _) => { + patch.add_statement(parent_end, s.kind.clone()); + } + ( + TransfromType::Discr, + StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))), + ) => { + let operand = Operand::Copy(Place::from(discr_local)); + let r_val = if f_c.const_.ty() == discr_ty { + Rvalue::Use(operand) + } else { + Rvalue::Cast(CastKind::IntToInt, operand, f_c.const_.ty()) + }; + patch.add_assign(parent_end, *lhs, r_val); + } + _ => unreachable!(), + } } } } diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 0c35f9838ed..ee6c154e6e8 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -214,6 +214,7 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{AllocId, ErrorHandled, GlobalAlloc, Scalar}; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; +use rustc_middle::mir::traversal; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Location, MentionedItem}; use rustc_middle::query::TyCtxtAt; @@ -1414,15 +1415,16 @@ fn collect_items_of_instance<'tcx>( }; if mode == CollectionMode::UsedItems { - // Visit everything. Here we rely on the visitor also visiting `required_consts`, so that we - // evaluate them and abort compilation if any of them errors. - collector.visit_body(body); - } else { - // We only need to evaluate all constants, but can ignore the rest of the MIR. - for const_op in &body.required_consts { - if let Some(val) = collector.eval_constant(const_op) { - collect_const_value(tcx, val, mentioned_items); - } + for (bb, data) in traversal::mono_reachable(body, tcx, instance) { + collector.visit_basic_block_data(bb, data) + } + } + + // Always visit all `required_consts`, so that we evaluate them and abort compilation if any of + // them errors. + for const_op in &body.required_consts { + if let Some(val) = collector.eval_constant(const_op) { + collect_const_value(tcx, val, mentioned_items); } } diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 1899517c0e2..6600b92fb31 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -69,7 +69,8 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc let (max_universe, variables) = canonicalizer.finalize(); - Canonical { max_universe, variables, value } + let defining_opaque_types = infcx.defining_opaque_types(); + Canonical { defining_opaque_types, max_universe, variables, value } } fn finalize(self) -> (ty::UniverseIndex, I::CanonicalVars) { @@ -349,6 +350,7 @@ impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) + | ty::Pat(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 69b48bf0aff..353c3f41ed8 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -34,8 +34,7 @@ use unescape_error_reporting::{emit_unescape_error, escaped_char}; rustc_data_structures::static_assert_size!(rustc_lexer::Token, 12); #[derive(Clone, Debug)] -pub struct UnmatchedDelim { - pub expected_delim: Delimiter, +pub(crate) struct UnmatchedDelim { pub found_delim: Option<Delimiter>, pub found_span: Span, pub unclosed_span: Option<Span>, diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index a506f98bf3a..b5a5a2a90ee 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -77,7 +77,6 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { for &(_, sp) in &self.diag_info.open_braces { err.span_label(sp, "unclosed delimiter"); self.diag_info.unmatched_delims.push(UnmatchedDelim { - expected_delim: Delimiter::Brace, found_delim: None, found_span: self.token.span, unclosed_span: Some(sp), @@ -163,9 +162,8 @@ impl<'psess, 'src> TokenTreesReader<'psess, 'src> { candidate = Some(*brace_span); } } - let (tok, _) = self.diag_info.open_braces.pop().unwrap(); + let (_, _) = self.diag_info.open_braces.pop().unwrap(); self.diag_info.unmatched_delims.push(UnmatchedDelim { - expected_delim: tok, found_delim: Some(close_delim), found_span: self.token.span, unclosed_span: unclosed_delimiter, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 80f2078fff2..51f288b3c95 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -153,7 +153,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { self.insert_def_id(def.non_enum_variant().fields[index].did); } ty::Tuple(..) => {} - _ => span_bug!(lhs.span, "named field access on non-ADT"), + ty::Error(_) => {} + kind => span_bug!(lhs.span, "named field access on non-ADT: {kind:?}"), } } diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs index dd6c1166957..51a69809c7a 100644 --- a/compiler/rustc_passes/src/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -161,4 +161,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { let mut inner_visitor = self.new_visitor(self.tcx); inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i)); } + + fn visit_pattern_type_pattern(&mut self, p: &'hir hir::Pat<'hir>) { + self.visit_pat(p) + } } diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index e6e52648d6f..72c6a714e4d 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -352,6 +352,7 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { TraitObject, Typeof, Infer, + Pat, Err ] ); @@ -611,6 +612,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { AnonStruct, AnonUnion, Path, + Pat, TraitObject, ImplTrait, Paren, diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index 467f09e4c29..548a7b43005 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -399,6 +399,7 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> { | ty::RawPtr(_, _) | ty::FnDef(_, _) | ty::FnPtr(_) + | ty::Pat(_, _) | ty::Dynamic(_, _, _) | ty::Closure(..) | ty::CoroutineClosure(..) diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 41d63407418..2039e994aaa 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -276,6 +276,7 @@ where | ty::Tuple(..) | ty::RawPtr(..) | ty::Ref(..) + | ty::Pat(..) | ty::FnPtr(..) | ty::Param(..) | ty::Bound(..) diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index c3fc036aed3..acc29b67ccc 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -101,7 +101,7 @@ where } pub struct VecCache<K: Idx, V> { - cache: Sharded<IndexVec<K, Option<(V, DepNodeIndex)>>>, + cache: Lock<IndexVec<K, Option<(V, DepNodeIndex)>>>, } impl<K: Idx, V> Default for VecCache<K, V> { @@ -120,24 +120,20 @@ where #[inline(always)] fn lookup(&self, key: &K) -> Option<(V, DepNodeIndex)> { - // FIXME: lock_shard_by_hash will use high bits which are usually zero in the index() passed - // here. This makes sharding essentially useless, always selecting the zero'th shard. - let lock = self.cache.lock_shard_by_hash(key.index() as u64); + let lock = self.cache.lock(); if let Some(Some(value)) = lock.get(*key) { Some(*value) } else { None } } #[inline] fn complete(&self, key: K, value: V, index: DepNodeIndex) { - let mut lock = self.cache.lock_shard_by_hash(key.index() as u64); + let mut lock = self.cache.lock(); lock.insert(key, (value, index)); } fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)) { - for shard in self.cache.lock_shards() { - for (k, v) in shard.iter_enumerated() { - if let Some(v) = v { - f(&k, &v.0, v.1); - } + for (k, v) in self.cache.lock().iter_enumerated() { + if let Some(v) = v { + f(&k, &v.0, v.1); } } } @@ -149,9 +145,6 @@ pub struct DefIdCache<V> { /// /// The second element of the tuple is the set of keys actually present in the IndexVec, used /// for faster iteration in `iter()`. - // FIXME: This may want to be sharded, like VecCache. However *how* to shard an IndexVec isn't - // super clear; VecCache is effectively not sharded today (see FIXME there). For now just omit - // that complexity here. local: Lock<(IndexVec<DefIndex, Option<(V, DepNodeIndex)>>, Vec<DefIndex>)>, foreign: DefaultCache<DefId, V>, } diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml new file mode 100644 index 00000000000..aea2f7dda7f --- /dev/null +++ b/compiler/rustc_sanitizers/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rustc_sanitizers" +version = "0.0.0" +edition = "2021" + +[dependencies] +bitflags = "2.5.0" +tracing = "0.1" +twox-hash = "1.6.3" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_middle = { path = "../rustc_middle" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/compiler/rustc_sanitizers/README.md b/compiler/rustc_sanitizers/README.md new file mode 100644 index 00000000000..d2e8f5d3a97 --- /dev/null +++ b/compiler/rustc_sanitizers/README.md @@ -0,0 +1,2 @@ +The `rustc_sanitizers` crate contains the source code for providing support for +the [sanitizers](https://github.com/google/sanitizers) to the Rust compiler. diff --git a/compiler/rustc_sanitizers/src/cfi/mod.rs b/compiler/rustc_sanitizers/src/cfi/mod.rs new file mode 100644 index 00000000000..90dab5e0333 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/mod.rs @@ -0,0 +1,6 @@ +//! LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI support for the Rust compiler. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +pub mod typeid; +pub use crate::cfi::typeid::{typeid_for_fnabi, typeid_for_instance, TypeIdOptions}; diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 7f223f13250..ed7cd8c2da7 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -1,76 +1,46 @@ -/// Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow -/// Integrity (CFI) and cross-language LLVM CFI support. -/// -/// Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium -/// C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that -/// are not used across the FFI boundary. -/// -/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, -/// see design document in the tracking issue #89653. +//! Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium +//! C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that +//! are not used across the FFI boundary. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. use rustc_data_structures::base_n; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::lang_items::LangItem; -use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::bug; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ - self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind, - TermKind, Ty, TyCtxt, UintTy, + self, Const, ExistentialPredicate, FloatTy, FnSig, GenericArg, GenericArgKind, GenericArgsRef, + IntTy, List, Region, RegionKind, TermKind, Ty, TyCtxt, TypeFoldable, UintTy, }; -use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; -use rustc_middle::ty::{TypeFoldable, TypeVisitableExt}; use rustc_span::def_id::DefId; use rustc_span::sym; -use rustc_target::abi::call::{Conv, FnAbi, PassMode}; use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::traits; use std::fmt::Write as _; -use std::iter; +use tracing::instrument; -use crate::typeid::TypeIdOptions; +use crate::cfi::typeid::itanium_cxx_abi::transform::{TransformTy, TransformTyOptions}; +use crate::cfi::typeid::TypeIdOptions; -/// Type and extended type qualifiers. -#[derive(Eq, Hash, PartialEq)] -enum TyQ { - None, - Const, - Mut, -} +/// Options for encode_ty. +pub type EncodeTyOptions = TypeIdOptions; /// Substitution dictionary key. #[derive(Eq, Hash, PartialEq)] -enum DictKey<'tcx> { +pub enum DictKey<'tcx> { Ty(Ty<'tcx>, TyQ), Region(Region<'tcx>), Const(Const<'tcx>), Predicate(ExistentialPredicate<'tcx>), } -/// Options for encode_ty. -type EncodeTyOptions = TypeIdOptions; - -/// Options for transform_ty. -type TransformTyOptions = TypeIdOptions; - -/// Converts a number to a disambiguator (see -/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>). -fn to_disambiguator(num: u64) -> String { - if let Some(num) = num.checked_sub(1) { - format!("s{}_", base_n::encode(num as u128, 62)) - } else { - "s_".to_string() - } -} - -/// Converts a number to a sequence number (see -/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>). -fn to_seq_id(num: usize) -> String { - if let Some(num) = num.checked_sub(1) { - base_n::encode(num as u128, 36).to_uppercase() - } else { - "".to_string() - } +/// Type and extended type qualifiers. +#[derive(Eq, Hash, PartialEq)] +pub enum TyQ { + None, + Const, + Mut, } /// Substitutes a component if found in the substitution dictionary (see @@ -91,6 +61,37 @@ fn compress<'tcx>( } } +/// Encodes args using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust +/// types that are not used at the FFI boundary. +fn encode_args<'tcx>( + tcx: TyCtxt<'tcx>, + args: GenericArgsRef<'tcx>, + dict: &mut FxHashMap<DictKey<'tcx>, usize>, + options: EncodeTyOptions, +) -> String { + // [I<subst1..substN>E] as part of vendor extended type + let mut s = String::new(); + let args: Vec<GenericArg<'_>> = args.iter().collect(); + if !args.is_empty() { + s.push('I'); + for arg in args { + match arg.unpack() { + GenericArgKind::Lifetime(region) => { + s.push_str(&encode_region(region, dict)); + } + GenericArgKind::Type(ty) => { + s.push_str(&encode_ty(tcx, ty, dict, options)); + } + GenericArgKind::Const(c) => { + s.push_str(&encode_const(tcx, c, dict, options)); + } + } + } + s.push('E'); + } + s +} + /// Encodes a const using the Itanium C++ ABI as a literal argument (see /// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>). fn encode_const<'tcx>( @@ -159,7 +160,6 @@ fn encode_const<'tcx>( /// Encodes a FnSig using the Itanium C++ ABI with vendor extended type qualifiers and types for /// Rust types that are not used at the FFI boundary. -#[instrument(level = "trace", skip(tcx, dict))] fn encode_fnsig<'tcx>( tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>, @@ -283,12 +283,12 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, s.push('E'); compress(dict, DictKey::Region(region), &mut s); } - // FIXME(@lcnr): Why is `ReEarlyParam` reachable here. - RegionKind::ReEarlyParam(..) | RegionKind::ReErased => { + RegionKind::ReErased => { s.push_str("u6region"); compress(dict, DictKey::Region(region), &mut s); } - RegionKind::ReLateParam(..) + RegionKind::ReEarlyParam(..) + | RegionKind::ReLateParam(..) | RegionKind::ReStatic | RegionKind::ReError(_) | RegionKind::ReVar(..) @@ -299,137 +299,10 @@ fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, s } -/// Encodes args using the Itanium C++ ABI with vendor extended type qualifiers and types for Rust -/// types that are not used at the FFI boundary. -fn encode_args<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, - dict: &mut FxHashMap<DictKey<'tcx>, usize>, - options: EncodeTyOptions, -) -> String { - // [I<subst1..substN>E] as part of vendor extended type - let mut s = String::new(); - let args: Vec<GenericArg<'_>> = args.iter().collect(); - if !args.is_empty() { - s.push('I'); - for arg in args { - match arg.unpack() { - GenericArgKind::Lifetime(region) => { - s.push_str(&encode_region(region, dict)); - } - GenericArgKind::Type(ty) => { - s.push_str(&encode_ty(tcx, ty, dict, options)); - } - GenericArgKind::Const(c) => { - s.push_str(&encode_const(tcx, c, dict, options)); - } - } - } - s.push('E'); - } - s -} - -/// Encodes a ty:Ty name, including its crate and path disambiguators and names. -fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { - // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where - // <element-type> is <subst>, using v0's <path> without v0's extended form of paths: - // - // N<namespace-tagN>..N<namespace-tag1> - // C<crate-disambiguator><crate-name> - // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN> - // - // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance: - // - // pub type Type1 = impl Send; - // let _: Type1 = <Struct1<i32>>::foo; - // fn foo1(_: Type1) { } - // - // pub type Type2 = impl Send; - // let _: Type2 = <Trait1<i32>>::foo; - // fn foo2(_: Type2) { } - // - // pub type Type3 = impl Send; - // let _: Type3 = <i32 as Trait1<i32>>::foo; - // fn foo3(_: Type3) { } - // - // pub type Type4 = impl Send; - // let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo; - // fn foo3(_: Type4) { } - // - // Are encoded as: - // - // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE - // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE - // - // The reason for not using v0's extended form of paths is to use a consistent and simpler - // encoding, as the reasoning for using it isn't relevant for type metadata identifiers (i.e., - // keep symbol names close to how methods are represented in error messages). See - // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods. - let mut s = String::new(); - - // Start and namespace tags - let mut def_path = tcx.def_path(def_id); - def_path.data.reverse(); - for disambiguated_data in &def_path.data { - s.push('N'); - s.push_str(match disambiguated_data.data { - hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace> - hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace> - hir::definitions::DefPathData::TypeNs(..) => "t", - hir::definitions::DefPathData::ValueNs(..) => "v", - hir::definitions::DefPathData::Closure => "C", - hir::definitions::DefPathData::Ctor => "c", - hir::definitions::DefPathData::AnonConst => "k", - hir::definitions::DefPathData::OpaqueTy => "i", - hir::definitions::DefPathData::CrateRoot - | hir::definitions::DefPathData::Use - | hir::definitions::DefPathData::GlobalAsm - | hir::definitions::DefPathData::MacroNs(..) - | hir::definitions::DefPathData::LifetimeNs(..) - | hir::definitions::DefPathData::AnonAdt => { - bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); - } - }); - } - - // Crate disambiguator and name - s.push('C'); - s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64())); - let crate_name = tcx.crate_name(def_path.krate).to_string(); - let _ = write!(s, "{}{}", crate_name.len(), &crate_name); - - // Disambiguators and names - def_path.data.reverse(); - for disambiguated_data in &def_path.data { - let num = disambiguated_data.disambiguator as u64; - if num > 0 { - s.push_str(&to_disambiguator(num)); - } - - let name = disambiguated_data.data.to_string(); - let _ = write!(s, "{}", name.len()); - - // Prepend a '_' if name starts with a digit or '_' - if let Some(first) = name.as_bytes().first() { - if first.is_ascii_digit() || *first == b'_' { - s.push('_'); - } - } else { - bug!("encode_ty_name: invalid name `{:?}`", name); - } - - s.push_str(&name); - } - - s -} - /// Encodes a ty:Ty using the Itanium C++ ABI with vendor extended type qualifiers and types for /// Rust types that are not used at the FFI boundary. -fn encode_ty<'tcx>( +#[instrument(level = "trace", skip(tcx, dict))] +pub fn encode_ty<'tcx>( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>, @@ -533,6 +406,16 @@ fn encode_ty<'tcx>( typeid.push_str(&s); } + ty::Pat(ty0, pat) => { + // u3patI<element-type><pattern>E as vendor extended type + let mut s = String::from("u3patI"); + s.push_str(&encode_ty(tcx, *ty0, dict, options)); + write!(s, "{:?}", **pat).unwrap(); + s.push('E'); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + ty::Slice(ty0) => { // u5sliceI<element-type>E as vendor extended type let mut s = String::from("u5sliceI"); @@ -752,501 +635,119 @@ fn encode_ty<'tcx>( typeid } -struct TransformTy<'tcx> { - tcx: TyCtxt<'tcx>, - options: TransformTyOptions, - parents: Vec<Ty<'tcx>>, -} - -impl<'tcx> TransformTy<'tcx> { - fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self { - TransformTy { tcx, options, parents: Vec::new() } - } -} - -impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { - // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms - // all c_void types into unit types unconditionally, generalizes pointers if - // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if - // TransformTyOptions::NORMALIZE_INTEGERS option is set. - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind() { - ty::Array(..) - | ty::Closure(..) - | ty::Coroutine(..) - | ty::CoroutineClosure(..) - | ty::CoroutineWitness(..) - | ty::Float(..) - | ty::FnDef(..) - | ty::Foreign(..) - | ty::Never - | ty::Slice(..) - | ty::Str - | ty::Tuple(..) => t.super_fold_with(self), - - ty::Bool => { - if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Note: on all platforms that Rust's currently supports, its size and alignment - // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs. - // - // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.) - // - // Clang represents bool as an 8-bit unsigned integer. - self.tcx.types.u8 - } else { - t - } - } - - ty::Char => { - if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Since #118032, char is guaranteed to have the same size, alignment, and - // function call ABI as u32 on all platforms. - self.tcx.types.u32 - } else { - t - } - } - - ty::Int(..) | ty::Uint(..) => { - if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit - // wide. All platforms we currently support have a C platform, and as a - // consequence, isize/usize are at least 16-bit wide for all of them. - // - // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.) - match t.kind() { - ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width { - 16 => self.tcx.types.i16, - 32 => self.tcx.types.i32, - 64 => self.tcx.types.i64, - 128 => self.tcx.types.i128, - _ => bug!( - "fold_ty: unexpected pointer width `{}`", - self.tcx.sess.target.pointer_width - ), - }, - ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width { - 16 => self.tcx.types.u16, - 32 => self.tcx.types.u32, - 64 => self.tcx.types.u64, - 128 => self.tcx.types.u128, - _ => bug!( - "fold_ty: unexpected pointer width `{}`", - self.tcx.sess.target.pointer_width - ), - }, - _ => t, - } - } else { - t - } - } - - ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit, - - ty::Adt(adt_def, args) => { - if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t) - { - // Don't transform repr(transparent) types with an user-defined CFI encoding to - // preserve the user-defined CFI encoding. - if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) { - return t; - } - let variant = adt_def.non_enum_variant(); - let param_env = self.tcx.param_env(variant.def_id); - let field = variant.fields.iter().find(|field| { - let ty = self.tcx.type_of(field.did).instantiate_identity(); - let is_zst = self - .tcx - .layout_of(param_env.and(ty)) - .is_ok_and(|layout| layout.is_zst()); - !is_zst - }); - if let Some(field) = field { - let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args); - // Generalize any repr(transparent) user-defined type that is either a - // pointer or reference, and either references itself or any other type that - // contains or references itself, to avoid a reference cycle. - - // If the self reference is not through a pointer, for example, due - // to using `PhantomData`, need to skip normalizing it if we hit it again. - self.parents.push(t); - let ty = if ty0.is_any_ptr() && ty0.contains(t) { - let options = self.options; - self.options |= TransformTyOptions::GENERALIZE_POINTERS; - let ty = ty0.fold_with(self); - self.options = options; - ty - } else { - ty0.fold_with(self) - }; - self.parents.pop(); - ty - } else { - // Transform repr(transparent) types without non-ZST field into () - self.tcx.types.unit - } - } else { - t.super_fold_with(self) - } - } - - ty::Ref(..) => { - if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if t.is_mutable_ptr() { - Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) - } else { - Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) - } - } else { - t.super_fold_with(self) - } - } - - ty::RawPtr(..) => { - if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - if t.is_mutable_ptr() { - Ty::new_mut_ptr(self.tcx, self.tcx.types.unit) - } else { - Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) - } - } else { - t.super_fold_with(self) - } - } - - ty::FnPtr(..) => { - if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { - Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) - } else { - t.super_fold_with(self) - } - } - - ty::Dynamic(predicates, _region, kind) => { - let predicates = self.tcx.mk_poly_existential_predicates_from_iter( - predicates.iter().filter_map(|predicate| match predicate.skip_binder() { - ty::ExistentialPredicate::Trait(trait_ref) => { - let trait_ref = ty::TraitRef::identity(self.tcx, trait_ref.def_id); - Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait( - ty::ExistentialTraitRef::erase_self_ty(self.tcx, trait_ref), - ))) - } - ty::ExistentialPredicate::Projection(..) => None, - ty::ExistentialPredicate::AutoTrait(..) => Some(predicate), - }), - ); - - Ty::new_dynamic(self.tcx, predicates, self.tcx.lifetimes.re_erased, *kind) - } - - ty::Alias(..) => { - self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t)) - } +/// Encodes a ty:Ty name, including its crate and path disambiguators and names. +fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String { + // Encode <name> for use in u<length><name>[I<element-type1..element-typeN>E], where + // <element-type> is <subst>, using v0's <path> without v0's extended form of paths: + // + // N<namespace-tagN>..N<namespace-tag1> + // C<crate-disambiguator><crate-name> + // <path-disambiguator1><path-name1>..<path-disambiguatorN><path-nameN> + // + // With additional tags for DefPathData::Impl and DefPathData::ForeignMod. For instance: + // + // pub type Type1 = impl Send; + // let _: Type1 = <Struct1<i32>>::foo; + // fn foo1(_: Type1) { } + // + // pub type Type2 = impl Send; + // let _: Type2 = <Trait1<i32>>::foo; + // fn foo2(_: Type2) { } + // + // pub type Type3 = impl Send; + // let _: Type3 = <i32 as Trait1<i32>>::foo; + // fn foo3(_: Type3) { } + // + // pub type Type4 = impl Send; + // let _: Type4 = <Struct1<i32> as Trait1<i32>>::foo; + // fn foo3(_: Type4) { } + // + // Are encoded as: + // + // _ZTSFvu29NvNIC1234_5crate8{{impl}}3fooIu3i32EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3dynIu21NtC1234_5crate6Trait1Iu3i32Eu6regionES_EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu3i32S_EE + // _ZTSFvu27NvNtC1234_5crate6Trait13fooIu22NtC1234_5crate7Struct1Iu3i32ES_EE + // + // The reason for not using v0's extended form of paths is to use a consistent and simpler + // encoding, as the reasoning for using it isn't relevant for type metadata identifiers (i.e., + // keep symbol names close to how methods are represented in error messages). See + // https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html#methods. + let mut s = String::new(); - ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { - bug!("fold_ty: unexpected `{:?}`", t.kind()); + // Start and namespace tags + let mut def_path = tcx.def_path(def_id); + def_path.data.reverse(); + for disambiguated_data in &def_path.data { + s.push('N'); + s.push_str(match disambiguated_data.data { + hir::definitions::DefPathData::Impl => "I", // Not specified in v0's <namespace> + hir::definitions::DefPathData::ForeignMod => "F", // Not specified in v0's <namespace> + hir::definitions::DefPathData::TypeNs(..) => "t", + hir::definitions::DefPathData::ValueNs(..) => "v", + hir::definitions::DefPathData::Closure => "C", + hir::definitions::DefPathData::Ctor => "c", + hir::definitions::DefPathData::AnonConst => "k", + hir::definitions::DefPathData::OpaqueTy => "i", + hir::definitions::DefPathData::CrateRoot + | hir::definitions::DefPathData::Use + | hir::definitions::DefPathData::GlobalAsm + | hir::definitions::DefPathData::MacroNs(..) + | hir::definitions::DefPathData::LifetimeNs(..) + | hir::definitions::DefPathData::AnonAdt => { + bug!("encode_ty_name: unexpected `{:?}`", disambiguated_data.data); } - } - } - - fn interner(&self) -> TyCtxt<'tcx> { - self.tcx + }); } -} - -/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor -/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. -#[instrument(level = "trace", skip(tcx))] -pub fn typeid_for_fnabi<'tcx>( - tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - options: TypeIdOptions, -) -> String { - // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions - // its type. - let mut typeid = String::from("_Z"); - - // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type - // metadata identifiers for function pointers. The typeinfo name encoding is a two-character - // code (i.e., 'TS') prefixed to the type encoding for the function. - typeid.push_str("TS"); - // Function types are delimited by an "F..E" pair - typeid.push('F'); - - // A dictionary of substitution candidates used for compression (see - // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). - let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default(); + // Crate disambiguator and name + s.push('C'); + s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64())); + let crate_name = tcx.crate_name(def_path.krate).to_string(); + let _ = write!(s, "{}{}", crate_name.len(), &crate_name); - let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - match fn_abi.conv { - Conv::C => { - encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); - } - _ => { - encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); + // Disambiguators and names + def_path.data.reverse(); + for disambiguated_data in &def_path.data { + let num = disambiguated_data.disambiguator as u64; + if num > 0 { + s.push_str(&to_disambiguator(num)); } - } - // Encode the return type - let transform_ty_options = TransformTyOptions::from_bits(options.bits()) - .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); - let mut type_folder = TransformTy::new(tcx, transform_ty_options); - let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - - // Encode the parameter types + let name = disambiguated_data.data.to_string(); + let _ = write!(s, "{}", name.len()); - // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how - // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR - // interpretation today will allow skipped arguments to simply not be passed at a call-site. - if !fn_abi.c_variadic { - let mut pushed_arg = false; - for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { - pushed_arg = true; - let ty = arg.layout.ty.fold_with(&mut type_folder); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - } - if !pushed_arg { - // Empty parameter lists, whether declared as () or conventionally as (void), are - // encoded with a void parameter specifier "v". - typeid.push('v'); - } - } else { - for n in 0..fn_abi.fixed_count as usize { - if fn_abi.args[n].mode == PassMode::Ignore { - continue; + // Prepend a '_' if name starts with a digit or '_' + if let Some(first) = name.as_bytes().first() { + if first.is_ascii_digit() || *first == b'_' { + s.push('_'); } - let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } else { + bug!("encode_ty_name: invalid name `{:?}`", name); } - typeid.push('z'); - } - - // Close the "F..E" pair - typeid.push('E'); - - // Add encoding suffixes - if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { - typeid.push_str(".normalized"); - } - - if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) { - typeid.push_str(".generalized"); + s.push_str(&name); } - typeid + s } -/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with -/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary. -pub fn typeid_for_instance<'tcx>( - tcx: TyCtxt<'tcx>, - mut instance: Instance<'tcx>, - options: TypeIdOptions, -) -> String { - if (matches!(instance.def, ty::InstanceDef::Virtual(..)) - && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn()) - || matches!(instance.def, ty::InstanceDef::DropGlue(..)) - { - // Adjust the type ids of DropGlues - // - // DropGlues may have indirect calls to one or more given types drop function. Rust allows - // for types to be erased to any trait object and retains the drop function for the original - // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is - // called a second time, it only has information after type erasure and it could be a call - // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on - // declaration/definition, and during code generation at call sites so they have the same - // type id and match. - // - // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of - // any other type. - // - let def_id = tcx - .lang_items() - .drop_trait() - .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); - let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { - def_id: def_id, - args: List::empty(), - }); - 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 { - let upcast_ty = match tcx.trait_of_item(def_id) { - Some(trait_id) => trait_object_ty( - tcx, - ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)), - ), - // drop_in_place won't have a defining trait, skip the upcast - None => instance.args.type_at(0), - }; - let stripped_ty = strip_receiver_auto(tcx, upcast_ty); - instance.args = tcx.mk_args_trait(stripped_ty, instance.args.into_iter().skip(1)); - } else if let ty::InstanceDef::VTableShim(def_id) = instance.def - && let Some(trait_id) = tcx.trait_of_item(def_id) - { - // VTableShims may have a trait method, but a concrete Self. This is not suitable for a vtable, - // as the caller will not know the concrete Self. - let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); - } - - if !options.contains(EncodeTyOptions::USE_CONCRETE_SELF) { - if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) - && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) - { - let impl_method = tcx.associated_item(instance.def_id()); - let method_id = impl_method - .trait_item_def_id - .expect("Part of a trait implementation, but not linked to the def_id?"); - let trait_method = tcx.associated_item(method_id); - let trait_id = trait_ref.skip_binder().def_id; - if traits::is_vtable_safe_method(tcx, trait_id, trait_method) - && tcx.object_safety_violations(trait_id).is_empty() - { - // Trait methods will have a Self polymorphic parameter, where the concreteized - // implementatation will not. We need to walk back to the more general trait method - let trait_ref = tcx.instantiate_and_normalize_erasing_regions( - instance.args, - ty::ParamEnv::reveal_all(), - trait_ref, - ); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - - // At the call site, any call to this concrete function through a vtable will be - // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the - // original method id, and we've recovered the trait arguments, we can make the callee - // instance we're computing the alias set for match the caller instance. - // - // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. - // 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); - 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); - } - } else if tcx.is_closure_like(instance.def_id()) { - // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, - // instantiate it, and take the type of its only method as our own. - let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - let (trait_id, inputs) = match closure_ty.kind() { - ty::Closure(..) => { - let closure_args = instance.args.as_closure(); - let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap(); - let tuple_args = - tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0]; - (trait_id, Some(tuple_args)) - } - ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() { - hir::CoroutineKind::Coroutine(..) => ( - tcx.require_lang_item(LangItem::Coroutine, None), - Some(instance.args.as_coroutine().resume_ty()), - ), - hir::CoroutineKind::Desugared(desugaring, _) => { - let lang_item = match desugaring { - hir::CoroutineDesugaring::Async => LangItem::Future, - hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, - hir::CoroutineDesugaring::Gen => LangItem::Iterator, - }; - (tcx.require_lang_item(lang_item, None), None) - } - }, - ty::CoroutineClosure(..) => ( - tcx.require_lang_item(LangItem::FnOnce, None), - Some( - tcx.instantiate_bound_regions_with_erased( - instance.args.as_coroutine_closure().coroutine_closure_sig(), - ) - .tupled_inputs_ty, - ), - ), - x => bug!("Unexpected type kind for closure-like: {x:?}"), - }; - let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into)); - let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args); - let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); - let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); - // There should be exactly one method on this trait, and it should be the one we're - // defining. - let call = tcx - .associated_items(trait_id) - .in_definition_order() - .find(|it| it.kind == ty::AssocKind::Fn) - .expect("No call-family function on closure-like Fn trait?") - .def_id; - - instance.def = ty::InstanceDef::Virtual(call, 0); - instance.args = abstract_args; - } +/// Converts a number to a disambiguator (see +/// <https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html>). +fn to_disambiguator(num: u64) -> String { + if let Some(num) = num.checked_sub(1) { + format!("s{}_", base_n::encode(num as u128, 62)) + } else { + "s_".to_string() } - - let fn_abi = tcx - .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) - .unwrap_or_else(|error| { - bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}") - }); - - typeid_for_fnabi(tcx, fn_abi, options) } -fn strip_receiver_auto<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty::Dynamic(preds, lifetime, kind) = ty.kind() else { - bug!("Tried to strip auto traits from non-dynamic type {ty}"); - }; - if preds.principal().is_some() { - let filtered_preds = - tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| { - !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..)) - })); - Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind) +/// Converts a number to a sequence number (see +/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id>). +fn to_seq_id(num: usize) -> String { + if let Some(num) = num.checked_sub(1) { + base_n::encode(num as u128, 36).to_uppercase() } else { - // If there's no principal type, re-encode it as a unit, since we don't know anything - // about it. This technically discards the knowledge that it was a type that was made - // into a trait object at some point, but that's not a lot. - tcx.types.unit + "".to_string() } } - -#[instrument(skip(tcx), ret)] -fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { - assert!(!poly_trait_ref.has_non_region_param()); - let principal_pred = poly_trait_ref.map_bound(|trait_ref| { - ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) - }); - let mut assoc_preds: Vec<_> = traits::supertraits(tcx, poly_trait_ref) - .flat_map(|super_poly_trait_ref| { - tcx.associated_items(super_poly_trait_ref.def_id()) - .in_definition_order() - .filter(|item| item.kind == ty::AssocKind::Type) - .map(move |assoc_ty| { - super_poly_trait_ref.map_bound(|super_trait_ref| { - let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args); - let resolved = tcx.normalize_erasing_regions( - ty::ParamEnv::reveal_all(), - alias_ty.to_ty(tcx), - ); - debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); - ty::ExistentialPredicate::Projection(ty::ExistentialProjection { - def_id: assoc_ty.def_id, - args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, - term: resolved.into(), - }) - }) - }) - }) - .collect(); - assoc_preds.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); - let preds = tcx.mk_poly_existential_predicates_from_iter( - iter::once(principal_pred).chain(assoc_preds.into_iter()), - ); - Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn) -} diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs new file mode 100644 index 00000000000..b6182dc4e63 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/mod.rs @@ -0,0 +1,123 @@ +//! Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow +//! Integrity (CFI) and cross-language LLVM CFI support. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::bug; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable}; +use rustc_target::abi::call::{Conv, FnAbi, PassMode}; +use tracing::instrument; + +mod encode; +mod transform; +use crate::cfi::typeid::itanium_cxx_abi::encode::{encode_ty, DictKey, EncodeTyOptions}; +use crate::cfi::typeid::itanium_cxx_abi::transform::{ + transform_instance, TransformTy, TransformTyOptions, +}; +use crate::cfi::typeid::TypeIdOptions; + +/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor +/// extended type qualifiers and types for Rust types that are not used at the FFI boundary. +#[instrument(level = "trace", skip(tcx))] +pub fn typeid_for_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + options: TypeIdOptions, +) -> String { + // A name is mangled by prefixing "_Z" to an encoding of its name, and in the case of functions + // its type. + let mut typeid = String::from("_Z"); + + // Clang uses the Itanium C++ ABI's virtual tables and RTTI typeinfo structure name as type + // metadata identifiers for function pointers. The typeinfo name encoding is a two-character + // code (i.e., 'TS') prefixed to the type encoding for the function. + typeid.push_str("TS"); + + // Function types are delimited by an "F..E" pair + typeid.push('F'); + + // A dictionary of substitution candidates used for compression (see + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). + let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default(); + + let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); + match fn_abi.conv { + Conv::C => { + encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C); + } + _ => { + encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C); + } + } + + // Encode the return type + let transform_ty_options = TransformTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits())); + let mut type_folder = TransformTy::new(tcx, transform_ty_options); + let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + + // Encode the parameter types + + // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how + // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR + // interpretation today will allow skipped arguments to simply not be passed at a call-site. + if !fn_abi.c_variadic { + let mut pushed_arg = false; + for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { + pushed_arg = true; + let ty = arg.layout.ty.fold_with(&mut type_folder); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + if !pushed_arg { + // Empty parameter lists, whether declared as () or conventionally as (void), are + // encoded with a void parameter specifier "v". + typeid.push('v'); + } + } else { + for n in 0..fn_abi.fixed_count as usize { + if fn_abi.args[n].mode == PassMode::Ignore { + continue; + } + let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + + typeid.push('z'); + } + + // Close the "F..E" pair + typeid.push('E'); + + // Add encoding suffixes + if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + typeid.push_str(".normalized"); + } + + if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) { + typeid.push_str(".generalized"); + } + + typeid +} + +/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with +/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary. +#[instrument(level = "trace", skip(tcx))] +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + options: TypeIdOptions, +) -> String { + let transform_ty_options = TransformTyOptions::from_bits(options.bits()) + .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits())); + let instance = transform_instance(tcx, instance, transform_ty_options); + let fn_abi = tcx + .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((instance, ty::List::empty()))) + .unwrap_or_else(|error| { + bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}") + }); + typeid_for_fnabi(tcx, fn_abi, options) +} 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 new file mode 100644 index 00000000000..7141c6c9bb0 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -0,0 +1,450 @@ +//! Transforms instances and types for LLVM CFI and cross-language LLVM CFI support using Itanium +//! C++ ABI mangling. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +use rustc_hir as hir; +use rustc_hir::LangItem; +use rustc_middle::bug; +use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; +use rustc_middle::ty::{ + self, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, UintTy, +}; +use rustc_span::sym; +use rustc_trait_selection::traits; +use std::iter; +use tracing::{debug, instrument}; + +use crate::cfi::typeid::itanium_cxx_abi::encode::EncodeTyOptions; +use crate::cfi::typeid::TypeIdOptions; + +/// Options for transform_ty. +pub type TransformTyOptions = TypeIdOptions; + +pub struct TransformTy<'tcx> { + tcx: TyCtxt<'tcx>, + options: TransformTyOptions, + parents: Vec<Ty<'tcx>>, +} + +impl<'tcx> TransformTy<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, options: TransformTyOptions) -> Self { + TransformTy { tcx, options, parents: Vec::new() } + } +} + +/// Transforms a ty:Ty for being encoded and used in the substitution dictionary. +/// +/// * Transforms all c_void types into unit types. +/// * Generalizes pointers if TransformTyOptions::GENERALIZE_POINTERS option is set. +/// * Normalizes integers if TransformTyOptions::NORMALIZE_INTEGERS option is set. +/// * Generalizes any repr(transparent) user-defined type that is either a pointer or reference, and +/// either references itself or any other type that contains or references itself, to avoid a +/// reference cycle. +/// * Transforms repr(transparent) types without non-ZST field into (). +/// +impl<'tcx> TypeFolder<TyCtxt<'tcx>> for TransformTy<'tcx> { + // Transforms a ty:Ty for being encoded and used in the substitution dictionary. + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.kind() { + ty::Array(..) + | ty::Closure(..) + | ty::Coroutine(..) + | ty::CoroutineClosure(..) + | ty::CoroutineWitness(..) + | ty::Dynamic(..) + | ty::Float(..) + | ty::FnDef(..) + | ty::Foreign(..) + | ty::Never + | ty::Pat(..) + | ty::Slice(..) + | ty::Str + | ty::Tuple(..) => t.super_fold_with(self), + + ty::Bool => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Note: on all platforms that Rust's currently supports, its size and alignment + // are 1, and its ABI class is INTEGER - see Rust Layout and ABIs. + // + // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.) + // + // Clang represents bool as an 8-bit unsigned integer. + self.tcx.types.u8 + } else { + t + } + } + + ty::Char => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Since #118032, char is guaranteed to have the same size, alignment, and + // function call ABI as u32 on all platforms. + self.tcx.types.u32 + } else { + t + } + } + + ty::Int(..) | ty::Uint(..) => { + if self.options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { + // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit + // wide. All platforms we currently support have a C platform, and as a + // consequence, isize/usize are at least 16-bit wide for all of them. + // + // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.) + match t.kind() { + ty::Int(IntTy::Isize) => match self.tcx.sess.target.pointer_width { + 16 => self.tcx.types.i16, + 32 => self.tcx.types.i32, + 64 => self.tcx.types.i64, + 128 => self.tcx.types.i128, + _ => bug!( + "fold_ty: unexpected pointer width `{}`", + self.tcx.sess.target.pointer_width + ), + }, + ty::Uint(UintTy::Usize) => match self.tcx.sess.target.pointer_width { + 16 => self.tcx.types.u16, + 32 => self.tcx.types.u32, + 64 => self.tcx.types.u64, + 128 => self.tcx.types.u128, + _ => bug!( + "fold_ty: unexpected pointer width `{}`", + self.tcx.sess.target.pointer_width + ), + }, + _ => t, + } + } else { + t + } + } + + ty::Adt(..) if t.is_c_void(self.tcx) => self.tcx.types.unit, + + ty::Adt(adt_def, args) => { + if adt_def.repr().transparent() && adt_def.is_struct() && !self.parents.contains(&t) + { + // Don't transform repr(transparent) types with an user-defined CFI encoding to + // preserve the user-defined CFI encoding. + if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) { + return t; + } + let variant = adt_def.non_enum_variant(); + let param_env = self.tcx.param_env(variant.def_id); + let field = variant.fields.iter().find(|field| { + let ty = self.tcx.type_of(field.did).instantiate_identity(); + let is_zst = self + .tcx + .layout_of(param_env.and(ty)) + .is_ok_and(|layout| layout.is_zst()); + !is_zst + }); + if let Some(field) = field { + let ty0 = self.tcx.type_of(field.did).instantiate(self.tcx, args); + // Generalize any repr(transparent) user-defined type that is either a + // pointer or reference, and either references itself or any other type that + // contains or references itself, to avoid a reference cycle. + + // If the self reference is not through a pointer, for example, due + // to using `PhantomData`, need to skip normalizing it if we hit it again. + self.parents.push(t); + let ty = if ty0.is_any_ptr() && ty0.contains(t) { + let options = self.options; + self.options |= TransformTyOptions::GENERALIZE_POINTERS; + let ty = ty0.fold_with(self); + self.options = options; + ty + } else { + ty0.fold_with(self) + }; + self.parents.pop(); + ty + } else { + // Transform repr(transparent) types without non-ZST field into () + self.tcx.types.unit + } + } else { + t.super_fold_with(self) + } + } + + ty::Ref(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if t.is_mutable_ptr() { + Ty::new_mut_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) + } else { + Ty::new_imm_ref(self.tcx, self.tcx.lifetimes.re_static, self.tcx.types.unit) + } + } else { + t.super_fold_with(self) + } + } + + ty::RawPtr(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + if t.is_mutable_ptr() { + Ty::new_mut_ptr(self.tcx, self.tcx.types.unit) + } else { + Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) + } + } else { + t.super_fold_with(self) + } + } + + ty::FnPtr(..) => { + if self.options.contains(TransformTyOptions::GENERALIZE_POINTERS) { + Ty::new_imm_ptr(self.tcx, self.tcx.types.unit) + } else { + t.super_fold_with(self) + } + } + + ty::Alias(..) => { + self.fold_ty(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), t)) + } + + ty::Bound(..) | ty::Error(..) | ty::Infer(..) | ty::Param(..) | ty::Placeholder(..) => { + bug!("fold_ty: unexpected `{:?}`", t.kind()); + } + } + } + + fn interner(&self) -> TyCtxt<'tcx> { + self.tcx + } +} + +#[instrument(skip(tcx), ret)] +fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>) -> Ty<'tcx> { + assert!(!poly_trait_ref.has_non_region_param()); + let principal_pred = poly_trait_ref.map_bound(|trait_ref| { + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)) + }); + let mut assoc_preds: Vec<_> = traits::supertraits(tcx, poly_trait_ref) + .flat_map(|super_poly_trait_ref| { + tcx.associated_items(super_poly_trait_ref.def_id()) + .in_definition_order() + .filter(|item| item.kind == ty::AssocKind::Type) + .map(move |assoc_ty| { + super_poly_trait_ref.map_bound(|super_trait_ref| { + let alias_ty = ty::AliasTy::new(tcx, assoc_ty.def_id, super_trait_ref.args); + let resolved = tcx.normalize_erasing_regions( + ty::ParamEnv::reveal_all(), + alias_ty.to_ty(tcx), + ); + debug!("Resolved {:?} -> {resolved}", alias_ty.to_ty(tcx)); + ty::ExistentialPredicate::Projection(ty::ExistentialProjection { + def_id: assoc_ty.def_id, + args: ty::ExistentialTraitRef::erase_self_ty(tcx, super_trait_ref).args, + term: resolved.into(), + }) + }) + }) + }) + .collect(); + assoc_preds.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); + let preds = tcx.mk_poly_existential_predicates_from_iter( + iter::once(principal_pred).chain(assoc_preds.into_iter()), + ); + Ty::new_dynamic(tcx, preds, tcx.lifetimes.re_erased, ty::Dyn) +} + +/// Transforms an instance for LLVM CFI and cross-language LLVM CFI support using Itanium C++ ABI +/// mangling. +/// +/// typeid_for_instance is called at two locations, initially when declaring/defining functions and +/// methods, and later during code generation at call sites, after type erasure might have ocurred. +/// +/// In the first call (i.e., when declaring/defining functions and methods), it encodes type ids for +/// an FnAbi or Instance, and these type ids are attached to functions and methods. (These type ids +/// are used later by the LowerTypeTests LLVM pass to aggregate functions in groups derived from +/// these type ids.) +/// +/// In the second call (i.e., during code generation at call sites), it encodes a type id for an +/// FnAbi or Instance, after type erasure might have occured, and this type id is used for testing +/// if a function is member of the group derived from this type id. Therefore, in the first call to +/// typeid_for_fnabi (when type ids are attached to functions and methods), it can only include at +/// most as much information that would be available in the second call (i.e., during code +/// generation at call sites); otherwise, the type ids would not not match. +/// +/// For this, it: +/// +/// * Adjust the type ids of DropGlues (see below). +/// * Adjusts the type ids of VTableShims to the type id expected in the call sites for the +/// entry in the vtable (i.e., by using the signature of the closure passed as an argument to the +/// shim, or by just removing self). +/// * Performs type erasure for calls on trait objects by transforming self into a trait object of +/// the trait that defines the method. +/// * Performs type erasure for closures call methods by transforming self into a trait object of +/// the Fn trait that defines the method (for being attached as a secondary type id). +/// +#[instrument(level = "trace", skip(tcx))] +pub fn transform_instance<'tcx>( + tcx: TyCtxt<'tcx>, + mut instance: Instance<'tcx>, + options: TransformTyOptions, +) -> Instance<'tcx> { + if (matches!(instance.def, ty::InstanceDef::Virtual(..)) + && Some(instance.def_id()) == tcx.lang_items().drop_in_place_fn()) + || matches!(instance.def, ty::InstanceDef::DropGlue(..)) + { + // Adjust the type ids of DropGlues + // + // DropGlues may have indirect calls to one or more given types drop function. Rust allows + // for types to be erased to any trait object and retains the drop function for the original + // type, which means at the indirect call sites in DropGlues, when typeid_for_fnabi is + // called a second time, it only has information after type erasure and it could be a call + // on any arbitrary trait object. Normalize them to a synthesized Drop trait object, both on + // declaration/definition, and during code generation at call sites so they have the same + // type id and match. + // + // FIXME(rcvalle): This allows a drop call on any trait object to call the drop function of + // any other type. + // + let def_id = tcx + .lang_items() + .drop_trait() + .unwrap_or_else(|| bug!("typeid_for_instance: couldn't get drop_trait lang item")); + let predicate = ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { + def_id: def_id, + args: List::empty(), + }); + 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 { + // 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) { + Some(trait_id) => trait_object_ty( + tcx, + ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)), + ), + // drop_in_place won't have a defining trait, skip the upcast + None => instance.args.type_at(0), + }; + let ty::Dynamic(preds, lifetime, kind) = upcast_ty.kind() else { + bug!("Tried to remove autotraits from non-dynamic type {upcast_ty}"); + }; + let self_ty = if preds.principal().is_some() { + let filtered_preds = + tcx.mk_poly_existential_predicates_from_iter(preds.into_iter().filter(|pred| { + !matches!(pred.skip_binder(), ty::ExistentialPredicate::AutoTrait(..)) + })); + Ty::new_dynamic(tcx, filtered_preds, *lifetime, *kind) + } else { + // If there's no principal type, re-encode it as a unit, since we don't know anything + // about it. This technically discards the knowledge that it was a type that was made + // into a trait object at some point, but that's not a lot. + 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 + && 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 + // entry in the vtable (i.e., by using the signature of the closure passed as an argument + // to the shim, or by just removing self). + let trait_ref = ty::TraitRef::new(tcx, trait_id, instance.args); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + instance.args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + } + + if !options.contains(TransformTyOptions::USE_CONCRETE_SELF) { + // Perform type erasure for calls on trait objects by transforming self into a trait object + // of the trait that defines the method. + if let Some(impl_id) = tcx.impl_of_method(instance.def_id()) + && let Some(trait_ref) = tcx.impl_trait_ref(impl_id) + { + let impl_method = tcx.associated_item(instance.def_id()); + let method_id = impl_method + .trait_item_def_id + .expect("Part of a trait implementation, but not linked to the def_id?"); + let trait_method = tcx.associated_item(method_id); + let trait_id = trait_ref.skip_binder().def_id; + if traits::is_vtable_safe_method(tcx, trait_id, trait_method) + && tcx.object_safety_violations(trait_id).is_empty() + { + // Trait methods will have a Self polymorphic parameter, where the concreteized + // implementatation will not. We need to walk back to the more general trait method + let trait_ref = tcx.instantiate_and_normalize_erasing_regions( + instance.args, + ty::ParamEnv::reveal_all(), + trait_ref, + ); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + + // At the call site, any call to this concrete function through a vtable will be + // `Virtual(method_id, idx)` with appropriate arguments for the method. Since we have the + // original method id, and we've recovered the trait arguments, we can make the callee + // instance we're computing the alias set for match the caller instance. + // + // Right now, our code ignores the vtable index everywhere, so we use 0 as a placeholder. + // 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); + 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); + } + } else if tcx.is_closure_like(instance.def_id()) { + // We're either a closure or a coroutine. Our goal is to find the trait we're defined on, + // instantiate it, and take the type of its only method as our own. + let closure_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); + let (trait_id, inputs) = match closure_ty.kind() { + ty::Closure(..) => { + let closure_args = instance.args.as_closure(); + let trait_id = tcx.fn_trait_kind_to_def_id(closure_args.kind()).unwrap(); + let tuple_args = + tcx.instantiate_bound_regions_with_erased(closure_args.sig()).inputs()[0]; + (trait_id, Some(tuple_args)) + } + ty::Coroutine(..) => match tcx.coroutine_kind(instance.def_id()).unwrap() { + hir::CoroutineKind::Coroutine(..) => ( + tcx.require_lang_item(LangItem::Coroutine, None), + Some(instance.args.as_coroutine().resume_ty()), + ), + hir::CoroutineKind::Desugared(desugaring, _) => { + let lang_item = match desugaring { + hir::CoroutineDesugaring::Async => LangItem::Future, + hir::CoroutineDesugaring::AsyncGen => LangItem::AsyncIterator, + hir::CoroutineDesugaring::Gen => LangItem::Iterator, + }; + (tcx.require_lang_item(lang_item, None), None) + } + }, + ty::CoroutineClosure(..) => ( + tcx.require_lang_item(LangItem::FnOnce, None), + Some( + tcx.instantiate_bound_regions_with_erased( + instance.args.as_coroutine_closure().coroutine_closure_sig(), + ) + .tupled_inputs_ty, + ), + ), + x => bug!("Unexpected type kind for closure-like: {x:?}"), + }; + let concrete_args = tcx.mk_args_trait(closure_ty, inputs.map(Into::into)); + let trait_ref = ty::TraitRef::new(tcx, trait_id, concrete_args); + let invoke_ty = trait_object_ty(tcx, ty::Binder::dummy(trait_ref)); + let abstract_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); + // There should be exactly one method on this trait, and it should be the one we're + // defining. + let call = tcx + .associated_items(trait_id) + .in_definition_order() + .find(|it| it.kind == ty::AssocKind::Fn) + .expect("No call-family function on closure-like Fn trait?") + .def_id; + + instance.def = ty::InstanceDef::Virtual(call, 0); + instance.args = abstract_args; + } + } + + instance +} diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs new file mode 100644 index 00000000000..ad8b1804439 --- /dev/null +++ b/compiler/rustc_sanitizers/src/cfi/typeid/mod.rs @@ -0,0 +1,54 @@ +//! Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI +//! support for the Rust compiler. +//! +//! For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, +//! see design document in the tracking issue #89653. +use bitflags::bitflags; +use rustc_middle::ty::{Instance, Ty, TyCtxt}; +use rustc_target::abi::call::FnAbi; + +bitflags! { + /// Options for typeid_for_fnabi. + #[derive(Clone, Copy, Debug)] + pub struct TypeIdOptions: u32 { + /// Generalizes pointers for compatibility with Clang + /// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI + /// support. + const GENERALIZE_POINTERS = 1; + /// Generalizes repr(C) user-defined type for extern function types with the "C" calling + /// convention (or extern types) for cross-language LLVM CFI and KCFI support. + const GENERALIZE_REPR_C = 2; + /// Normalizes integers for compatibility with Clang + /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM + /// CFI and KCFI support. + const NORMALIZE_INTEGERS = 4; + /// Do not perform self type erasure for attaching a secondary type id to methods with their + /// concrete self so they can be used as function pointers. + /// + /// (This applies to typeid_for_instance only and should be used to attach a secondary type + /// id to methods during their declaration/definition so they match the type ids returned by + /// either typeid_for_instance or typeid_for_fnabi at call sites during code generation for + /// type membership tests when methods are used as function pointers.) + const USE_CONCRETE_SELF = 8; + } +} + +pub mod itanium_cxx_abi; + +/// Returns a type metadata identifier for the specified FnAbi. +pub fn typeid_for_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + options: TypeIdOptions, +) -> String { + itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options) +} + +/// Returns a type metadata identifier for the specified Instance. +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + options: TypeIdOptions, +) -> String { + itanium_cxx_abi::typeid_for_instance(tcx, instance, options) +} diff --git a/compiler/rustc_sanitizers/src/kcfi/mod.rs b/compiler/rustc_sanitizers/src/kcfi/mod.rs new file mode 100644 index 00000000000..a8b632940b0 --- /dev/null +++ b/compiler/rustc_sanitizers/src/kcfi/mod.rs @@ -0,0 +1,7 @@ +//! LLVM Kernel Control Flow Integrity (KCFI) and cross-language LLVM KCFI support for the Rust +//! compiler. +//! +//! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler, +//! see the tracking issue #123479. +pub mod typeid; +pub use crate::kcfi::typeid::{typeid_for_fnabi, typeid_for_instance, TypeIdOptions}; diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs new file mode 100644 index 00000000000..436c398e39b --- /dev/null +++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs @@ -0,0 +1,55 @@ +//! Type metadata identifiers for LLVM Kernel Control Flow Integrity (KCFI) and cross-language LLVM +//! KCFI support for the Rust compiler. +//! +//! 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_target::abi::call::FnAbi; +use std::hash::Hasher; +use twox_hash::XxHash64; + +pub use crate::cfi::typeid::{itanium_cxx_abi, TypeIdOptions}; + +/// Returns a KCFI type metadata identifier for the specified FnAbi. +pub fn typeid_for_fnabi<'tcx>( + tcx: TyCtxt<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + options: TypeIdOptions, +) -> u32 { + // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the + // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) + let mut hash: XxHash64 = Default::default(); + hash.write(itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes()); + hash.finish() as u32 +} + +/// Returns a KCFI type metadata identifier for the specified Instance. +pub fn typeid_for_instance<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, + mut options: TypeIdOptions, +) -> u32 { + // KCFI support for Rust shares most of its implementation with the CFI support, with some key + // differences: + // + // 1. KCFI performs type tests differently and are implemented as different LLVM passes than CFI + // to not require LTO. + // 2. KCFI has the limitation that a function or method may have one type id assigned only. + // + // Because of the limitation listed above (2), the current KCFI implementation (not CFI) does + // reifying of types (i.e., adds shims/trampolines for indirect calls in these cases) for: + // + // * Supporting casting between function items, closures, and Fn trait objects. + // * Supporting methods being cast as function pointers. + // + // 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))) { + options.insert(TypeIdOptions::USE_CONCRETE_SELF); + } + // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the + // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) + let mut hash: XxHash64 = Default::default(); + hash.write(itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes()); + hash.finish() as u32 +} diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs new file mode 100644 index 00000000000..1f73e255490 --- /dev/null +++ b/compiler/rustc_sanitizers/src/lib.rs @@ -0,0 +1,7 @@ +#![feature(let_chains)] +//! Sanitizers support for the Rust compiler. +//! +//! This crate contains the source code for providing support for the sanitizers to the Rust +//! compiler. +pub mod cfi; +pub mod kcfi; diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index d51fcf693ed..a4919b25fe3 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -10,19 +10,16 @@ use crate::search_paths::SearchPath; use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind}; use crate::{filesearch, lint, HashStableContext}; use crate::{EarlyDiagCtxt, Session}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey}; use rustc_errors::emitter::HumanReadableErrorType; use rustc_errors::{ColorConfig, DiagArgValue, DiagCtxtFlags, IntoDiagArg}; use rustc_feature::UnstableFeatures; use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION}; use rustc_span::source_map::FilePathMapping; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::{FileName, FileNameDisplayPreference, RealFileName, SourceFileHashAlgorithm}; -use rustc_target::abi::Align; use rustc_target::spec::LinkSelfContainedComponents; -use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet, SplitDebuginfo}; -use rustc_target::spec::{Target, TargetTriple, TARGETS}; +use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple}; use std::collections::btree_map::{ Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter, }; @@ -36,8 +33,11 @@ use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use std::sync::LazyLock; +mod cfg; pub mod sigpipe; +pub use cfg::{Cfg, CheckCfg, ExpectedValues}; + /// The different settings that the `-C strip` flag can have. #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum Strip { @@ -1201,346 +1201,10 @@ pub(crate) const fn default_lib_output() -> CrateType { CrateType::Rlib } -fn default_configuration(sess: &Session) -> Cfg { - let mut ret = Cfg::default(); - - macro_rules! ins_none { - ($key:expr) => { - ret.insert(($key, None)); - }; - } - macro_rules! ins_str { - ($key:expr, $val_str:expr) => { - ret.insert(($key, Some(Symbol::intern($val_str)))); - }; - } - macro_rules! ins_sym { - ($key:expr, $val_sym:expr) => { - ret.insert(($key, Some($val_sym))); - }; - } - - // Symbols are inserted in alphabetical order as much as possible. - // The exceptions are where control flow forces things out of order. - // - // Run `rustc --print cfg` to see the configuration in practice. - // - // NOTE: These insertions should be kept in sync with - // `CheckCfg::fill_well_known` below. - - if sess.opts.debug_assertions { - ins_none!(sym::debug_assertions); - } - - if sess.overflow_checks() { - ins_none!(sym::overflow_checks); - } - - ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); - - // JUSTIFICATION: before wrapper fn is available - #[allow(rustc::bad_opt_access)] - if sess.opts.crate_types.contains(&CrateType::ProcMacro) { - ins_none!(sym::proc_macro); - } - - if sess.is_nightly_build() { - ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol()); - } - - for mut s in sess.opts.unstable_opts.sanitizer { - // KASAN is still ASAN under the hood, so it uses the same attribute. - if s == SanitizerSet::KERNELADDRESS { - s = SanitizerSet::ADDRESS; - } - ins_str!(sym::sanitize, &s.to_string()); - } - - if sess.is_sanitizer_cfi_generalize_pointers_enabled() { - ins_none!(sym::sanitizer_cfi_generalize_pointers); - } - if sess.is_sanitizer_cfi_normalize_integers_enabled() { - ins_none!(sym::sanitizer_cfi_normalize_integers); - } - - ins_str!(sym::target_abi, &sess.target.abi); - ins_str!(sym::target_arch, &sess.target.arch); - ins_str!(sym::target_endian, sess.target.endian.as_str()); - ins_str!(sym::target_env, &sess.target.env); - - for family in sess.target.families.as_ref() { - ins_str!(sym::target_family, family); - if family == "windows" { - ins_none!(sym::windows); - } else if family == "unix" { - ins_none!(sym::unix); - } - } - - // `target_has_atomic*` - let layout = sess.target.parse_data_layout().unwrap_or_else(|err| { - sess.dcx().emit_fatal(err); - }); - let mut has_atomic = false; - for (i, align) in [ - (8, layout.i8_align.abi), - (16, layout.i16_align.abi), - (32, layout.i32_align.abi), - (64, layout.i64_align.abi), - (128, layout.i128_align.abi), - ] { - if i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() { - if !has_atomic { - has_atomic = true; - if sess.is_nightly_build() { - if sess.target.atomic_cas { - ins_none!(sym::target_has_atomic); - } - ins_none!(sym::target_has_atomic_load_store); - } - } - let mut insert_atomic = |sym, align: Align| { - if sess.target.atomic_cas { - ins_sym!(sym::target_has_atomic, sym); - } - if align.bits() == i { - ins_sym!(sym::target_has_atomic_equal_alignment, sym); - } - ins_sym!(sym::target_has_atomic_load_store, sym); - }; - insert_atomic(sym::integer(i), align); - if sess.target.pointer_width as u64 == i { - insert_atomic(sym::ptr, layout.pointer_align.abi); - } - } - } - - ins_str!(sym::target_os, &sess.target.os); - ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width)); - - if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) { - ins_none!(sym::target_thread_local); - } - - ins_str!(sym::target_vendor, &sess.target.vendor); - - // If the user wants a test runner, then add the test cfg. - if sess.is_test_crate() { - ins_none!(sym::test); - } - - ret -} - -/// The parsed `--cfg` options that define the compilation environment of the -/// crate, used to drive conditional compilation. -/// -/// An `FxIndexSet` is used to ensure deterministic ordering of error messages -/// relating to `--cfg`. -pub type Cfg = FxIndexSet<(Symbol, Option<Symbol>)>; - -/// The parsed `--check-cfg` options. -#[derive(Default)] -pub struct CheckCfg { - /// Is well known names activated - pub exhaustive_names: bool, - /// Is well known values activated - pub exhaustive_values: bool, - /// All the expected values for a config name - pub expecteds: FxHashMap<Symbol, ExpectedValues<Symbol>>, - /// Well known names (only used for diagnostics purposes) - pub well_known_names: FxHashSet<Symbol>, -} - -pub enum ExpectedValues<T> { - Some(FxHashSet<Option<T>>), - Any, -} - -impl<T: Eq + Hash> ExpectedValues<T> { - fn insert(&mut self, value: T) -> bool { - match self { - ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)), - ExpectedValues::Any => false, - } - } -} - -impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> { - fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { - match self { - ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)), - ExpectedValues::Any => {} - } - } -} - -impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> { - fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { - match self { - ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))), - ExpectedValues::Any => {} - } - } -} - -impl CheckCfg { - pub fn fill_well_known(&mut self, current_target: &Target) { - if !self.exhaustive_values && !self.exhaustive_names { - return; - } - - let no_values = || { - let mut values = FxHashSet::default(); - values.insert(None); - ExpectedValues::Some(values) - }; - - let empty_values = || { - let values = FxHashSet::default(); - ExpectedValues::Some(values) - }; - - macro_rules! ins { - ($name:expr, $values:expr) => {{ - self.well_known_names.insert($name); - self.expecteds.entry($name).or_insert_with($values) - }}; - } - - // Symbols are inserted in alphabetical order as much as possible. - // The exceptions are where control flow forces things out of order. - // - // NOTE: This should be kept in sync with `default_configuration`. - // Note that symbols inserted conditionally in `default_configuration` - // are inserted unconditionally here. - // - // When adding a new config here you should also update - // `tests/ui/check-cfg/well-known-values.rs`. - // - // Don't forget to update `src/doc/unstable-book/src/compiler-flags/check-cfg.md` - // in the unstable book as well! - - ins!(sym::debug_assertions, no_values); - - // These four are never set by rustc, but we set them anyway: they - // should not trigger a lint because `cargo clippy`, `cargo doc`, - // `cargo test` and `cargo miri run` (respectively) can set them. - ins!(sym::clippy, no_values); - ins!(sym::doc, no_values); - ins!(sym::doctest, no_values); - ins!(sym::miri, no_values); - - ins!(sym::overflow_checks, no_values); - - ins!(sym::panic, empty_values).extend(&PanicStrategy::all()); - - ins!(sym::proc_macro, no_values); - - ins!(sym::relocation_model, empty_values).extend(RelocModel::all()); - - let sanitize_values = SanitizerSet::all() - .into_iter() - .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap())); - ins!(sym::sanitize, empty_values).extend(sanitize_values); - - ins!(sym::sanitizer_cfi_generalize_pointers, no_values); - ins!(sym::sanitizer_cfi_normalize_integers, no_values); - - ins!(sym::target_feature, empty_values).extend( - rustc_target::target_features::all_known_features() - .map(|(f, _sb)| f) - .chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned()) - .map(Symbol::intern), - ); - - // sym::target_* - { - const VALUES: [&Symbol; 8] = [ - &sym::target_abi, - &sym::target_arch, - &sym::target_endian, - &sym::target_env, - &sym::target_family, - &sym::target_os, - &sym::target_pointer_width, - &sym::target_vendor, - ]; - - // Initialize (if not already initialized) - for &e in VALUES { - if !self.exhaustive_values { - ins!(e, || ExpectedValues::Any); - } else { - ins!(e, empty_values); - } - } - - if self.exhaustive_values { - // Get all values map at once otherwise it would be costly. - // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). - let [ - values_target_abi, - values_target_arch, - values_target_endian, - values_target_env, - values_target_family, - values_target_os, - values_target_pointer_width, - values_target_vendor, - ] = self - .expecteds - .get_many_mut(VALUES) - .expect("unable to get all the check-cfg values buckets"); - - for target in TARGETS - .iter() - .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) - .chain(iter::once(current_target.clone())) - { - values_target_abi.insert(Symbol::intern(&target.options.abi)); - values_target_arch.insert(Symbol::intern(&target.arch)); - values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); - values_target_env.insert(Symbol::intern(&target.options.env)); - values_target_family.extend( - target.options.families.iter().map(|family| Symbol::intern(family)), - ); - values_target_os.insert(Symbol::intern(&target.options.os)); - values_target_pointer_width.insert(sym::integer(target.pointer_width)); - values_target_vendor.insert(Symbol::intern(&target.options.vendor)); - } - } - } - - let atomic_values = &[ - sym::ptr, - sym::integer(8usize), - sym::integer(16usize), - sym::integer(32usize), - sym::integer(64usize), - sym::integer(128usize), - ]; - for sym in [ - sym::target_has_atomic, - sym::target_has_atomic_equal_alignment, - sym::target_has_atomic_load_store, - ] { - ins!(sym, no_values).extend(atomic_values); - } - - ins!(sym::target_thread_local, no_values); - - ins!(sym::test, no_values); - - ins!(sym::unix, no_values); - ins!(sym::windows, no_values); - } -} - pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { // Combine the configuration requested by the session (command line) with // some default and generated configuration items. - user_cfg.extend(default_configuration(sess)); + user_cfg.extend(cfg::default_configuration(sess)); user_cfg } diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs new file mode 100644 index 00000000000..34dcd0cf598 --- /dev/null +++ b/compiler/rustc_session/src/config/cfg.rs @@ -0,0 +1,379 @@ +//! cfg and check-cfg configuration +//! +//! This module contains the definition of [`Cfg`] and [`CheckCfg`] +//! as well as the logic for creating the default configuration for a +//! given [`Session`]. +//! +//! It also contains the filling of the well known configs, which should +//! ALWAYS be in sync with the default_configuration. +//! +//! ## Adding a new cfg +//! +//! Adding a new feature requires two new symbols one for the cfg it-self +//! and the second one for the unstable feature gate, those are defined in +//! `rustc_span::symbol`. +//! +//! As well as the following points, +//! - Add the activation logic in [`default_configuration`] +//! - Add the cfg to [`CheckCfg::fill_well_known`] (and related files), +//! so that the compiler can know the cfg is expected +//! - Add the feature gating in `compiler/rustc_feature/src/builtin_attrs.rs` + +use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::Align; +use rustc_target::spec::{PanicStrategy, RelocModel, SanitizerSet}; +use rustc_target::spec::{Target, TargetTriple, TARGETS}; + +use crate::config::CrateType; +use crate::Session; + +use std::hash::Hash; +use std::iter; + +/// The parsed `--cfg` options that define the compilation environment of the +/// crate, used to drive conditional compilation. +/// +/// An `FxIndexSet` is used to ensure deterministic ordering of error messages +/// relating to `--cfg`. +pub type Cfg = FxIndexSet<(Symbol, Option<Symbol>)>; + +/// The parsed `--check-cfg` options. +#[derive(Default)] +pub struct CheckCfg { + /// Is well known names activated + pub exhaustive_names: bool, + /// Is well known values activated + pub exhaustive_values: bool, + /// All the expected values for a config name + pub expecteds: FxHashMap<Symbol, ExpectedValues<Symbol>>, + /// Well known names (only used for diagnostics purposes) + pub well_known_names: FxHashSet<Symbol>, +} + +pub enum ExpectedValues<T> { + Some(FxHashSet<Option<T>>), + Any, +} + +impl<T: Eq + Hash> ExpectedValues<T> { + fn insert(&mut self, value: T) -> bool { + match self { + ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)), + ExpectedValues::Any => false, + } + } +} + +impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> { + fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) { + match self { + ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)), + ExpectedValues::Any => {} + } + } +} + +impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> { + fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) { + match self { + ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))), + ExpectedValues::Any => {} + } + } +} + +/// Generate the default configs for a given session +pub(crate) fn default_configuration(sess: &Session) -> Cfg { + let mut ret = Cfg::default(); + + macro_rules! ins_none { + ($key:expr) => { + ret.insert(($key, None)); + }; + } + macro_rules! ins_str { + ($key:expr, $val_str:expr) => { + ret.insert(($key, Some(Symbol::intern($val_str)))); + }; + } + macro_rules! ins_sym { + ($key:expr, $val_sym:expr) => { + ret.insert(($key, Some($val_sym))); + }; + } + + // Symbols are inserted in alphabetical order as much as possible. + // The exceptions are where control flow forces things out of order. + // + // Run `rustc --print cfg` to see the configuration in practice. + // + // NOTE: These insertions should be kept in sync with + // `CheckCfg::fill_well_known` below. + + if sess.opts.debug_assertions { + ins_none!(sym::debug_assertions); + } + + if sess.overflow_checks() { + ins_none!(sym::overflow_checks); + } + + ins_sym!(sym::panic, sess.panic_strategy().desc_symbol()); + + // JUSTIFICATION: before wrapper fn is available + #[allow(rustc::bad_opt_access)] + if sess.opts.crate_types.contains(&CrateType::ProcMacro) { + ins_none!(sym::proc_macro); + } + + if sess.is_nightly_build() { + ins_sym!(sym::relocation_model, sess.target.relocation_model.desc_symbol()); + } + + for mut s in sess.opts.unstable_opts.sanitizer { + // KASAN is still ASAN under the hood, so it uses the same attribute. + if s == SanitizerSet::KERNELADDRESS { + s = SanitizerSet::ADDRESS; + } + ins_str!(sym::sanitize, &s.to_string()); + } + + if sess.is_sanitizer_cfi_generalize_pointers_enabled() { + ins_none!(sym::sanitizer_cfi_generalize_pointers); + } + if sess.is_sanitizer_cfi_normalize_integers_enabled() { + ins_none!(sym::sanitizer_cfi_normalize_integers); + } + + ins_str!(sym::target_abi, &sess.target.abi); + ins_str!(sym::target_arch, &sess.target.arch); + ins_str!(sym::target_endian, sess.target.endian.as_str()); + ins_str!(sym::target_env, &sess.target.env); + + for family in sess.target.families.as_ref() { + ins_str!(sym::target_family, family); + if family == "windows" { + ins_none!(sym::windows); + } else if family == "unix" { + ins_none!(sym::unix); + } + } + + // `target_has_atomic*` + let layout = sess.target.parse_data_layout().unwrap_or_else(|err| { + sess.dcx().emit_fatal(err); + }); + let mut has_atomic = false; + for (i, align) in [ + (8, layout.i8_align.abi), + (16, layout.i16_align.abi), + (32, layout.i32_align.abi), + (64, layout.i64_align.abi), + (128, layout.i128_align.abi), + ] { + if i >= sess.target.min_atomic_width() && i <= sess.target.max_atomic_width() { + if !has_atomic { + has_atomic = true; + if sess.is_nightly_build() { + if sess.target.atomic_cas { + ins_none!(sym::target_has_atomic); + } + ins_none!(sym::target_has_atomic_load_store); + } + } + let mut insert_atomic = |sym, align: Align| { + if sess.target.atomic_cas { + ins_sym!(sym::target_has_atomic, sym); + } + if align.bits() == i { + ins_sym!(sym::target_has_atomic_equal_alignment, sym); + } + ins_sym!(sym::target_has_atomic_load_store, sym); + }; + insert_atomic(sym::integer(i), align); + if sess.target.pointer_width as u64 == i { + insert_atomic(sym::ptr, layout.pointer_align.abi); + } + } + } + + ins_str!(sym::target_os, &sess.target.os); + ins_sym!(sym::target_pointer_width, sym::integer(sess.target.pointer_width)); + + if sess.opts.unstable_opts.has_thread_local.unwrap_or(sess.target.has_thread_local) { + ins_none!(sym::target_thread_local); + } + + ins_str!(sym::target_vendor, &sess.target.vendor); + + // If the user wants a test runner, then add the test cfg. + if sess.is_test_crate() { + ins_none!(sym::test); + } + + if sess.ub_checks() { + ins_none!(sym::ub_checks); + } + + ret +} + +impl CheckCfg { + /// Fill the current [`CheckCfg`] with all the well known cfgs + pub fn fill_well_known(&mut self, current_target: &Target) { + if !self.exhaustive_values && !self.exhaustive_names { + return; + } + + // for `#[cfg(foo)]` (ie. cfg value is none) + let no_values = || { + let mut values = FxHashSet::default(); + values.insert(None); + ExpectedValues::Some(values) + }; + + // preparation for inserting some values + let empty_values = || { + let values = FxHashSet::default(); + ExpectedValues::Some(values) + }; + + macro_rules! ins { + ($name:expr, $values:expr) => {{ + self.well_known_names.insert($name); + self.expecteds.entry($name).or_insert_with($values) + }}; + } + + // Symbols are inserted in alphabetical order as much as possible. + // The exceptions are where control flow forces things out of order. + // + // NOTE: This should be kept in sync with `default_configuration`. + // Note that symbols inserted conditionally in `default_configuration` + // are inserted unconditionally here. + // + // When adding a new config here you should also update + // `tests/ui/check-cfg/well-known-values.rs` (in order to test the + // expected values of the new config) and bless the all directory. + // + // Don't forget to update `src/doc/unstable-book/src/compiler-flags/check-cfg.md` + // in the unstable book as well! + + ins!(sym::debug_assertions, no_values); + + // These four are never set by rustc, but we set them anyway: they + // should not trigger a lint because `cargo clippy`, `cargo doc`, + // `cargo test` and `cargo miri run` (respectively) can set them. + ins!(sym::clippy, no_values); + ins!(sym::doc, no_values); + ins!(sym::doctest, no_values); + ins!(sym::miri, no_values); + + ins!(sym::overflow_checks, no_values); + + ins!(sym::panic, empty_values).extend(&PanicStrategy::all()); + + ins!(sym::proc_macro, no_values); + + ins!(sym::relocation_model, empty_values).extend(RelocModel::all()); + + let sanitize_values = SanitizerSet::all() + .into_iter() + .map(|sanitizer| Symbol::intern(sanitizer.as_str().unwrap())); + ins!(sym::sanitize, empty_values).extend(sanitize_values); + + ins!(sym::sanitizer_cfi_generalize_pointers, no_values); + ins!(sym::sanitizer_cfi_normalize_integers, no_values); + + ins!(sym::target_feature, empty_values).extend( + rustc_target::target_features::all_known_features() + .map(|(f, _sb)| f) + .chain(rustc_target::target_features::RUSTC_SPECIFIC_FEATURES.iter().cloned()) + .map(Symbol::intern), + ); + + // sym::target_* + { + const VALUES: [&Symbol; 8] = [ + &sym::target_abi, + &sym::target_arch, + &sym::target_endian, + &sym::target_env, + &sym::target_family, + &sym::target_os, + &sym::target_pointer_width, + &sym::target_vendor, + ]; + + // Initialize (if not already initialized) + for &e in VALUES { + if !self.exhaustive_values { + ins!(e, || ExpectedValues::Any); + } else { + ins!(e, empty_values); + } + } + + if self.exhaustive_values { + // Get all values map at once otherwise it would be costly. + // (8 values * 220 targets ~= 1760 times, at the time of writing this comment). + let [ + values_target_abi, + values_target_arch, + values_target_endian, + values_target_env, + values_target_family, + values_target_os, + values_target_pointer_width, + values_target_vendor, + ] = self + .expecteds + .get_many_mut(VALUES) + .expect("unable to get all the check-cfg values buckets"); + + for target in TARGETS + .iter() + .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target))) + .chain(iter::once(current_target.clone())) + { + values_target_abi.insert(Symbol::intern(&target.options.abi)); + values_target_arch.insert(Symbol::intern(&target.arch)); + values_target_endian.insert(Symbol::intern(target.options.endian.as_str())); + values_target_env.insert(Symbol::intern(&target.options.env)); + values_target_family.extend( + target.options.families.iter().map(|family| Symbol::intern(family)), + ); + values_target_os.insert(Symbol::intern(&target.options.os)); + values_target_pointer_width.insert(sym::integer(target.pointer_width)); + values_target_vendor.insert(Symbol::intern(&target.options.vendor)); + } + } + } + + let atomic_values = &[ + sym::ptr, + sym::integer(8usize), + sym::integer(16usize), + sym::integer(32usize), + sym::integer(64usize), + sym::integer(128usize), + ]; + for sym in [ + sym::target_has_atomic, + sym::target_has_atomic_equal_alignment, + sym::target_has_atomic_load_store, + ] { + ins!(sym, no_values).extend(atomic_values); + } + + ins!(sym::target_thread_local, no_values); + + ins!(sym::test, no_values); + + ins!(sym::ub_checks, no_values); + + ins!(sym::unix, no_values); + ins!(sym::windows, no_values); + } +} diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index a0f5eb59b6a..cb6656bae06 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -4,12 +4,10 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; -use crate::Session; use rustc_ast as ast; use rustc_data_structures::sync::{self, AppendOnlyIndexVec, FreezeLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; -use rustc_span::hygiene::{ExpnHash, ExpnId}; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -220,22 +218,6 @@ pub trait CrateStore: std::fmt::Debug { fn crate_name(&self, cnum: CrateNum) -> Symbol; fn stable_crate_id(&self, cnum: CrateNum) -> StableCrateId; fn stable_crate_id_to_crate_num(&self, stable_crate_id: StableCrateId) -> CrateNum; - - /// Fetch a DefId from a DefPathHash for a foreign crate. - fn def_path_hash_to_def_id(&self, cnum: CrateNum, hash: DefPathHash) -> DefId; - fn expn_hash_to_expn_id( - &self, - sess: &Session, - cnum: CrateNum, - index_guess: u32, - hash: ExpnHash, - ) -> ExpnId; - - /// Imports all `SourceFile`s from the given crate into the current session. - /// This normally happens automatically when we decode a `Span` from - /// that crate's metadata - however, the incr comp cache needs - /// to trigger this manually when decoding a foreign `Span` - fn import_source_files(&self, sess: &Session, cnum: CrateNum); } pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend; diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a76eb6b06aa..5e7c2465097 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1992,6 +1992,9 @@ written to standard error output)"), "in diagnostics, use heuristics to shorten paths referring to items"), tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], "select processor to schedule for (`rustc --print target-cpus` for details)"), + #[rustc_lint_opt_deny_field_access("use `Session::ub_checks` instead of this field")] + ub_checks: Option<bool> = (None, parse_opt_bool, [TRACKED], + "emit runtime checks for Undefined Behavior (default: -Cdebug-assertions)"), ui_testing: bool = (false, parse_bool, [UNTRACKED], "emit compiler diagnostics in a form suitable for UI testing (default: no)"), uninit_const_chunk_threshold: usize = (16, parse_number, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 55fff4421ae..22ca8a3cf3e 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -735,6 +735,10 @@ impl Session { self.opts.cg.overflow_checks.unwrap_or(self.opts.debug_assertions) } + pub fn ub_checks(&self) -> bool { + self.opts.unstable_opts.ub_checks.unwrap_or(self.opts.debug_assertions) + } + pub fn relocation_model(&self) -> RelocModel { self.opts.cg.relocation_model.unwrap_or(self.target.relocation_model) } diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index e8cc41cc886..0893bc31bfa 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -10,12 +10,12 @@ use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; -use stable_mir::mir::{Mutability, Place, ProjectionElem, Safety}; +use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety}; use stable_mir::ty::{ Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, - GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind, - TraitRef, Ty, UintTy, VariantDef, VariantIdx, + GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Pattern, Region, RigidTy, Span, + TermKind, TraitRef, Ty, UintTy, VariantDef, VariantIdx, }; use stable_mir::{CrateItem, CrateNum, DefId}; @@ -76,6 +76,19 @@ impl RustcInternal for Ty { } } +impl RustcInternal for Pattern { + type T<'tcx> = rustc_ty::Pattern<'tcx>; + fn internal<'tcx>(&self, tables: &mut Tables<'_>, tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + tcx.mk_pat(match self { + Pattern::Range { start, end, include_end } => rustc_ty::PatternKind::Range { + start: start.as_ref().map(|c| ty_const(c, tables, tcx)), + end: end.as_ref().map(|c| ty_const(c, tables, tcx)), + include_end: *include_end, + }, + }) + } +} + impl RustcInternal for RigidTy { type T<'tcx> = rustc_ty::TyKind<'tcx>; @@ -90,6 +103,9 @@ impl RustcInternal for RigidTy { RigidTy::Array(ty, cnst) => { rustc_ty::TyKind::Array(ty.internal(tables, tcx), ty_const(cnst, tables, tcx)) } + RigidTy::Pat(ty, pat) => { + rustc_ty::TyKind::Pat(ty.internal(tables, tcx), pat.internal(tables, tcx)) + } RigidTy::Adt(def, args) => { rustc_ty::TyKind::Adt(def.internal(tables, tcx), args.internal(tables, tcx)) } @@ -535,6 +551,38 @@ impl RustcInternal for ProjectionElem { } } +impl RustcInternal for BinOp { + type T<'tcx> = rustc_middle::mir::BinOp; + + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + match self { + BinOp::Add => rustc_middle::mir::BinOp::Add, + BinOp::AddUnchecked => rustc_middle::mir::BinOp::AddUnchecked, + BinOp::Sub => rustc_middle::mir::BinOp::Sub, + BinOp::SubUnchecked => rustc_middle::mir::BinOp::SubUnchecked, + BinOp::Mul => rustc_middle::mir::BinOp::Mul, + BinOp::MulUnchecked => rustc_middle::mir::BinOp::MulUnchecked, + BinOp::Div => rustc_middle::mir::BinOp::Div, + BinOp::Rem => rustc_middle::mir::BinOp::Rem, + BinOp::BitXor => rustc_middle::mir::BinOp::BitXor, + BinOp::BitAnd => rustc_middle::mir::BinOp::BitAnd, + BinOp::BitOr => rustc_middle::mir::BinOp::BitOr, + BinOp::Shl => rustc_middle::mir::BinOp::Shl, + BinOp::ShlUnchecked => rustc_middle::mir::BinOp::ShlUnchecked, + BinOp::Shr => rustc_middle::mir::BinOp::Shr, + BinOp::ShrUnchecked => rustc_middle::mir::BinOp::ShrUnchecked, + BinOp::Eq => rustc_middle::mir::BinOp::Eq, + BinOp::Lt => rustc_middle::mir::BinOp::Lt, + BinOp::Le => rustc_middle::mir::BinOp::Le, + BinOp::Ne => rustc_middle::mir::BinOp::Ne, + BinOp::Ge => rustc_middle::mir::BinOp::Ge, + BinOp::Gt => rustc_middle::mir::BinOp::Gt, + BinOp::Cmp => rustc_middle::mir::BinOp::Cmp, + BinOp::Offset => rustc_middle::mir::BinOp::Offset, + } + } +} + impl<T> RustcInternal for &T where T: RustcInternal, diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 7c12168b809..61bbedf9eec 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; -use stable_mir::mir::{Body, Place}; +use stable_mir::mir::{BinOp, Body, Place}; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -668,6 +668,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let tcx = tables.tcx; format!("{:?}", place.internal(&mut *tables, tcx)) } + + fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let rhs_internal = rhs.internal(&mut *tables, tcx); + let lhs_internal = lhs.internal(&mut *tables, tcx); + let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal); + ty.stable(&mut *tables) + } } pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index 2ad8f350f10..112e44f674e 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -330,6 +330,9 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { ty::Array(ty, constant) => { TyKind::RigidTy(RigidTy::Array(ty.stable(tables), constant.stable(tables))) } + ty::Pat(ty, pat) => { + TyKind::RigidTy(RigidTy::Pat(ty.stable(tables), pat.stable(tables))) + } ty::Slice(ty) => TyKind::RigidTy(RigidTy::Slice(ty.stable(tables))), ty::RawPtr(ty, mutbl) => { TyKind::RigidTy(RigidTy::RawPtr(ty.stable(tables), mutbl.stable(tables))) @@ -385,6 +388,20 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> { } } +impl<'tcx> Stable<'tcx> for ty::Pattern<'tcx> { + type T = stable_mir::ty::Pattern; + + fn stable(&self, tables: &mut Tables<'_>) -> Self::T { + match **self { + ty::PatternKind::Range { start, end, include_end } => stable_mir::ty::Pattern::Range { + start: start.stable(tables), + end: end.stable(tables), + include_end, + }, + } + } +} + impl<'tcx> Stable<'tcx> for ty::Const<'tcx> { type T = stable_mir::ty::Const; diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 770624d331d..f721a04d6b9 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -654,6 +654,12 @@ impl SourceMap { }) } + /// Extends the span to include any trailing whitespace, or returns the original + /// span if a `SpanSnippetError` was encountered. + pub fn span_extend_while_whitespace(&self, span: Span) -> Span { + self.span_extend_while(span, char::is_whitespace).unwrap_or(span) + } + /// Extends the given `Span` to previous character while the previous character matches the predicate pub fn span_extend_prev_while( &self, @@ -1034,12 +1040,9 @@ impl SourceMap { /// // ^^^^^^ input /// ``` pub fn mac_call_stmt_semi_span(&self, mac_call: Span) -> Option<Span> { - let span = self.span_extend_while(mac_call, char::is_whitespace).ok()?; - let span = span.shrink_to_hi().with_hi(BytePos(span.hi().0.checked_add(1)?)); - if self.span_to_snippet(span).as_deref() != Ok(";") { - return None; - } - Some(span) + let span = self.span_extend_while_whitespace(mac_call); + let span = self.next_point(span); + if self.span_to_snippet(span).as_deref() == Ok(";") { Some(span) } else { None } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ea0f7adf6f9..bfd0f77c237 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -514,6 +514,7 @@ symbols! { cfg_target_has_atomic_equal_alignment, cfg_target_thread_local, cfg_target_vendor, + cfg_ub_checks, cfg_version, cfi, cfi_encoding, @@ -1008,6 +1009,7 @@ symbols! { io_stderr, io_stdout, irrefutable_let_patterns, + is, is_val_statically_known, isa_attribute, isize, @@ -1346,6 +1348,8 @@ symbols! { path, pattern_complexity, pattern_parentheses, + pattern_type, + pattern_types, phantom_data, pic, pie, diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml index 1c8f1d03670..65aa9e40c8b 100644 --- a/compiler/rustc_symbol_mangling/Cargo.toml +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] # tidy-alphabetical-start -bitflags = "2.4.1" punycode = "0.4.0" rustc-demangle = "0.1.21" rustc_data_structures = { path = "../rustc_data_structures" } @@ -15,7 +14,5 @@ rustc_middle = { path = "../rustc_middle" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_target = { path = "../rustc_target" } -rustc_trait_selection = { path = "../rustc_trait_selection" } tracing = "0.1" -twox-hash = "1.6.3" # tidy-alphabetical-end diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 0588af9bda7..b9509478702 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -114,7 +114,6 @@ mod v0; pub mod errors; pub mod test; -pub mod typeid; /// This function computes the symbol name for the given `instance` and the /// given instantiating crate. That is, if you know that instance X is diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs deleted file mode 100644 index 7bd998294dd..00000000000 --- a/compiler/rustc_symbol_mangling/src/typeid.rs +++ /dev/null @@ -1,100 +0,0 @@ -/// Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI -/// support. -/// -/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler, -/// see design document in the tracking issue #89653. -use bitflags::bitflags; -use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt}; -use rustc_target::abi::call::FnAbi; -use std::hash::Hasher; -use twox_hash::XxHash64; - -bitflags! { - /// Options for typeid_for_fnabi. - #[derive(Clone, Copy, Debug)] - pub struct TypeIdOptions: u32 { - /// Generalizes pointers for compatibility with Clang - /// `-fsanitize-cfi-icall-generalize-pointers` option for cross-language LLVM CFI and KCFI - /// support. - const GENERALIZE_POINTERS = 1; - /// Generalizes repr(C) user-defined type for extern function types with the "C" calling - /// convention (or extern types) for cross-language LLVM CFI and KCFI support. - const GENERALIZE_REPR_C = 2; - /// Normalizes integers for compatibility with Clang - /// `-fsanitize-cfi-icall-experimental-normalize-integers` option for cross-language LLVM - /// CFI and KCFI support. - const NORMALIZE_INTEGERS = 4; - /// Do not perform self type erasure for attaching a secondary type id to methods with their - /// concrete self so they can be used as function pointers. - /// - /// (This applies to typeid_for_instance only and should be used to attach a secondary type - /// id to methods during their declaration/definition so they match the type ids returned by - /// either typeid_for_instance or typeid_for_fnabi at call sites during code generation for - /// type membership tests when methods are used as function pointers.) - const USE_CONCRETE_SELF = 8; - } -} - -mod typeid_itanium_cxx_abi; - -/// Returns a type metadata identifier for the specified FnAbi. -pub fn typeid_for_fnabi<'tcx>( - tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - options: TypeIdOptions, -) -> String { - typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options) -} - -/// Returns a type metadata identifier for the specified Instance. -pub fn typeid_for_instance<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - options: TypeIdOptions, -) -> String { - typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options) -} - -/// Returns a KCFI type metadata identifier for the specified FnAbi. -pub fn kcfi_typeid_for_fnabi<'tcx>( - tcx: TyCtxt<'tcx>, - fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - options: TypeIdOptions, -) -> u32 { - // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the - // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) - let mut hash: XxHash64 = Default::default(); - hash.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes()); - hash.finish() as u32 -} - -/// Returns a KCFI type metadata identifier for the specified Instance. -pub fn kcfi_typeid_for_instance<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, - mut options: TypeIdOptions, -) -> u32 { - // KCFI support for Rust shares most of its implementation with the CFI support, with some key - // differences: - // - // 1. KCFI performs type tests differently and are implemented as different LLVM passes than CFI - // to not require LTO. - // 2. KCFI has the limitation that a function or method may have one type id assigned only. - // - // Because of the limitation listed above (2), the current KCFI implementation (not CFI) does - // reifying of types (i.e., adds shims/trampolines for indirect calls in these cases) for: - // - // * Supporting casting between function items, closures, and Fn trait objects. - // * Supporting methods being cast as function pointers. - // - // 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))) { - options.insert(TypeIdOptions::USE_CONCRETE_SELF); - } - // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the - // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.) - let mut hash: XxHash64 = Default::default(); - hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes()); - hash.finish() as u32 -} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 8cb5370bb4a..cb255fabfe2 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -45,8 +45,8 @@ pub(super) fn mangle<'tcx>( 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::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"), @@ -371,6 +371,25 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { ty.print(self)?; } + ty::Pat(ty, pat) => match *pat { + ty::PatternKind::Range { start, end, include_end } => { + let consts = [ + start.unwrap_or(self.tcx.consts.unit), + end.unwrap_or(self.tcx.consts.unit), + ty::Const::from_bool(self.tcx, include_end).into(), + ]; + // HACK: Represent as tuple until we have something better. + // HACK: constants are used in arrays, even if the types don't match. + self.push("T"); + ty.print(self)?; + for ct in consts { + Ty::new_array_with_const_len(self.tcx, self.tcx.types.unit, ct) + .print(self)?; + } + self.push("E"); + } + }, + ty::Array(ty, len) => { self.push("A"); ty.print(self)?; diff --git a/compiler/rustc_target/src/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs index f99f6a3b721..04020d13f22 100644 --- a/compiler/rustc_target/src/abi/call/aarch64.rs +++ b/compiler/rustc_target/src/abi/call/aarch64.rs @@ -31,7 +31,7 @@ where RegKind::Vector => size.bits() == 64 || size.bits() == 128, }; - valid_unit.then_some(Uniform { unit, total: size }) + valid_unit.then_some(Uniform::consecutive(unit, size)) }) } @@ -60,7 +60,7 @@ where let size = ret.layout.size; let bits = size.bits(); if bits <= 128 { - ret.cast_to(Uniform { unit: Reg::i64(), total: size }); + ret.cast_to(Uniform::new(Reg::i64(), size)); return; } ret.make_indirect(); @@ -100,9 +100,9 @@ where }; if size.bits() <= 128 { if align.bits() == 128 { - arg.cast_to(Uniform { unit: Reg::i128(), total: size }); + arg.cast_to(Uniform::new(Reg::i128(), size)); } else { - arg.cast_to(Uniform { unit: Reg::i64(), total: size }); + arg.cast_to(Uniform::new(Reg::i64(), size)); } return; } diff --git a/compiler/rustc_target/src/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs index 95f6691d42a..9371e1b3958 100644 --- a/compiler/rustc_target/src/abi/call/arm.rs +++ b/compiler/rustc_target/src/abi/call/arm.rs @@ -21,7 +21,7 @@ where RegKind::Vector => size.bits() == 64 || size.bits() == 128, }; - valid_unit.then_some(Uniform { unit, total: size }) + valid_unit.then_some(Uniform::consecutive(unit, size)) }) } @@ -49,7 +49,7 @@ where let size = ret.layout.size; let bits = size.bits(); if bits <= 32 { - ret.cast_to(Uniform { unit: Reg::i32(), total: size }); + ret.cast_to(Uniform::new(Reg::i32(), size)); return; } ret.make_indirect(); @@ -78,7 +78,7 @@ where let align = arg.layout.align.abi.bytes(); let total = arg.layout.size; - arg.cast_to(Uniform { unit: if align <= 4 { Reg::i32() } else { Reg::i64() }, total }); + arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total)); } pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/compiler/rustc_target/src/abi/call/csky.rs b/compiler/rustc_target/src/abi/call/csky.rs index 8b4328db52e..7951f28beea 100644 --- a/compiler/rustc_target/src/abi/call/csky.rs +++ b/compiler/rustc_target/src/abi/call/csky.rs @@ -18,7 +18,7 @@ fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) { if total.bits() > 64 { arg.make_indirect(); } else if total.bits() > 32 { - arg.cast_to(Uniform { unit: Reg::i32(), total }); + arg.cast_to(Uniform::new(Reg::i32(), total)); } else { arg.cast_to(Reg::i32()); } @@ -38,7 +38,7 @@ fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) { if arg.layout.is_aggregate() { let total = arg.layout.size; if total.bits() > 32 { - arg.cast_to(Uniform { unit: Reg::i32(), total }); + arg.cast_to(Uniform::new(Reg::i32(), total)); } else { arg.cast_to(Reg::i32()); } diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs index 35d4b331cb4..943b12a9fbf 100644 --- a/compiler/rustc_target/src/abi/call/loongarch.rs +++ b/compiler/rustc_target/src/abi/call/loongarch.rs @@ -195,7 +195,7 @@ where if total.bits() <= xlen { arg.cast_to(xlen_reg); } else { - arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) }); + arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2))); } return false; } @@ -278,10 +278,10 @@ fn classify_arg<'a, Ty, C>( if total.bits() > xlen { let align_regs = align > xlen; if is_loongarch_aggregate(arg) { - arg.cast_to(Uniform { - unit: if align_regs { double_xlen_reg } else { xlen_reg }, - total: Size::from_bits(xlen * 2), - }); + arg.cast_to(Uniform::new( + if align_regs { double_xlen_reg } else { xlen_reg }, + Size::from_bits(xlen * 2), + )); } if align_regs && is_vararg { *avail_gprs -= *avail_gprs % 2; diff --git a/compiler/rustc_target/src/abi/call/mips.rs b/compiler/rustc_target/src/abi/call/mips.rs index 57ccfe2152b..0e5a7f37a09 100644 --- a/compiler/rustc_target/src/abi/call/mips.rs +++ b/compiler/rustc_target/src/abi/call/mips.rs @@ -27,7 +27,7 @@ where if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); - arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32); + arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32); } else { arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs index 2700f67b209..b2a2c34b980 100644 --- a/compiler/rustc_target/src/abi/call/mips64.rs +++ b/compiler/rustc_target/src/abi/call/mips64.rs @@ -68,7 +68,7 @@ where } // Cast to a uniform int structure - ret.cast_to(Uniform { unit: Reg::i64(), total: size }); + ret.cast_to(Uniform::new(Reg::i64(), size)); } else { ret.make_indirect(); } @@ -139,7 +139,7 @@ where let rest_size = size - Size::from_bytes(8) * prefix_index as u64; arg.cast_to(CastTarget { prefix, - rest: Uniform { unit: Reg::i64(), total: rest_size }, + rest: Uniform::new(Reg::i64(), rest_size), attrs: ArgAttributes { regular: ArgAttribute::default(), arg_ext: ArgExtension::None, diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index cdd3f0afd79..4502df339d1 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -255,11 +255,16 @@ pub struct Uniform { /// for 64-bit integers with a total size of 20 bytes. When the argument is actually passed, /// this size will be rounded up to the nearest multiple of `unit.size`. pub total: Size, + + /// Indicate that the argument is consecutive, in the sense that either all values need to be + /// passed in register, or all on the stack. If they are passed on the stack, there should be + /// no additional padding between elements. + pub is_consecutive: bool, } impl From<Reg> for Uniform { fn from(unit: Reg) -> Uniform { - Uniform { unit, total: unit.size } + Uniform { unit, total: unit.size, is_consecutive: false } } } @@ -267,6 +272,18 @@ impl Uniform { pub fn align<C: HasDataLayout>(&self, cx: &C) -> Align { self.unit.align(cx) } + + /// Pass using one or more values of the given type, without requiring them to be consecutive. + /// That is, some values may be passed in register and some on the stack. + pub fn new(unit: Reg, total: Size) -> Self { + Uniform { unit, total, is_consecutive: false } + } + + /// Pass using one or more consecutive values of the given type. Either all values will be + /// passed in registers, or all on the stack. + pub fn consecutive(unit: Reg, total: Size) -> Self { + Uniform { unit, total, is_consecutive: true } + } } /// Describes the type used for `PassMode::Cast`. diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs index 5c040ce9c3b..f85fa2419f0 100644 --- a/compiler/rustc_target/src/abi/call/nvptx64.rs +++ b/compiler/rustc_target/src/abi/call/nvptx64.rs @@ -35,7 +35,7 @@ where 16 => Reg::i128(), _ => unreachable!("Align is given as power of 2 no larger than 16 bytes"), }; - arg.cast_to(Uniform { unit, total: Size::from_bytes(2 * align_bytes) }); + arg.cast_to(Uniform::new(unit, Size::from_bytes(2 * align_bytes))); } else { // FIXME: find a better way to do this. See https://github.com/rust-lang/rust/issues/117271. arg.make_direct_deprecated(); diff --git a/compiler/rustc_target/src/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs index 2d41f77e50e..11a6cb52bab 100644 --- a/compiler/rustc_target/src/abi/call/powerpc64.rs +++ b/compiler/rustc_target/src/abi/call/powerpc64.rs @@ -2,7 +2,7 @@ // Alignment of 128 bit types is not currently handled, this will // need to be fixed when PowerPC vector support is added. -use crate::abi::call::{ArgAbi, FnAbi, Reg, RegKind, Uniform}; +use crate::abi::call::{Align, ArgAbi, FnAbi, Reg, RegKind, Uniform}; use crate::abi::{Endian, HasDataLayout, TyAbiInterface}; use crate::spec::HasTargetSpec; @@ -37,7 +37,7 @@ where RegKind::Vector => arg.layout.size.bits() == 128, }; - valid_unit.then_some(Uniform { unit, total: arg.layout.size }) + valid_unit.then_some(Uniform::consecutive(unit, arg.layout.size)) }) } @@ -81,7 +81,7 @@ where Reg::i64() }; - ret.cast_to(Uniform { unit, total: size }); + ret.cast_to(Uniform::new(unit, size)); return; } @@ -108,18 +108,20 @@ where } let size = arg.layout.size; - let (unit, total) = if size.bits() <= 64 { + if size.bits() <= 64 { // Aggregates smaller than a doubleword should appear in // the least-significant bits of the parameter doubleword. - (Reg { kind: RegKind::Integer, size }, size) + arg.cast_to(Reg { kind: RegKind::Integer, size }) } else { - // Aggregates larger than a doubleword should be padded - // at the tail to fill out a whole number of doublewords. - let reg_i64 = Reg::i64(); - (reg_i64, size.align_to(reg_i64.align(cx))) + // Aggregates larger than i64 should be padded at the tail to fill out a whole number + // of i64s or i128s, depending on the aggregate alignment. Always use an array for + // this, even if there is only a single element. + let reg = if arg.layout.align.abi.bytes() > 8 { Reg::i128() } else { Reg::i64() }; + arg.cast_to(Uniform::consecutive( + reg, + size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()), + )) }; - - arg.cast_to(Uniform { unit, total }); } pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs index 6a38496dc57..5d4b3a9d245 100644 --- a/compiler/rustc_target/src/abi/call/riscv.rs +++ b/compiler/rustc_target/src/abi/call/riscv.rs @@ -201,7 +201,7 @@ where if total.bits() <= xlen { arg.cast_to(xlen_reg); } else { - arg.cast_to(Uniform { unit: xlen_reg, total: Size::from_bits(xlen * 2) }); + arg.cast_to(Uniform::new(xlen_reg, Size::from_bits(xlen * 2))); } return false; } @@ -284,10 +284,10 @@ fn classify_arg<'a, Ty, C>( if total.bits() > xlen { let align_regs = align > xlen; if is_riscv_aggregate(arg) { - arg.cast_to(Uniform { - unit: if align_regs { double_xlen_reg } else { xlen_reg }, - total: Size::from_bits(xlen * 2), - }); + arg.cast_to(Uniform::new( + if align_regs { double_xlen_reg } else { xlen_reg }, + Size::from_bits(xlen * 2), + )); } if align_regs && is_vararg { *avail_gprs -= *avail_gprs % 2; diff --git a/compiler/rustc_target/src/abi/call/sparc.rs b/compiler/rustc_target/src/abi/call/sparc.rs index 57ccfe2152b..0e5a7f37a09 100644 --- a/compiler/rustc_target/src/abi/call/sparc.rs +++ b/compiler/rustc_target/src/abi/call/sparc.rs @@ -27,7 +27,7 @@ where if arg.layout.is_aggregate() { let pad_i32 = !offset.is_aligned(align); - arg.cast_to_and_pad_i32(Uniform { unit: Reg::i32(), total: size }, pad_i32); + arg.cast_to_and_pad_i32(Uniform::new(Reg::i32(), size), pad_i32); } else { arg.extend_integer_width_to(32); } diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs index cbed5b4afc1..acdcd5cc0d4 100644 --- a/compiler/rustc_target/src/abi/call/sparc64.rs +++ b/compiler/rustc_target/src/abi/call/sparc64.rs @@ -192,7 +192,7 @@ where arg.cast_to(CastTarget { prefix: data.prefix, - rest: Uniform { unit: Reg::i64(), total: rest_size }, + rest: Uniform::new(Reg::i64(), rest_size), attrs: ArgAttributes { regular: data.arg_attribute, arg_ext: ArgExtension::None, @@ -205,7 +205,7 @@ where } } - arg.cast_to(Uniform { unit: Reg::i64(), total }); + arg.cast_to(Uniform::new(Reg::i64(), total)); } pub fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>) diff --git a/compiler/rustc_target/src/abi/call/wasm.rs b/compiler/rustc_target/src/abi/call/wasm.rs index a7a2b314a94..a773fb1e814 100644 --- a/compiler/rustc_target/src/abi/call/wasm.rs +++ b/compiler/rustc_target/src/abi/call/wasm.rs @@ -1,4 +1,4 @@ -use crate::abi::call::{ArgAbi, FnAbi, Uniform}; +use crate::abi::call::{ArgAbi, FnAbi}; use crate::abi::{HasDataLayout, TyAbiInterface}; fn unwrap_trivial_aggregate<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool @@ -10,7 +10,7 @@ where if let Some(unit) = val.layout.homogeneous_aggregate(cx).ok().and_then(|ha| ha.unit()) { let size = val.layout.size; if unit.size == size { - val.cast_to(Uniform { unit, total: size }); + val.cast_to(unit); return true; } } diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs index 96da0b6fd1f..021457b145f 100644 --- a/compiler/rustc_target/src/spec/base/apple/mod.rs +++ b/compiler/rustc_target/src/spec/base/apple/mod.rs @@ -368,6 +368,11 @@ fn watchos_deployment_target() -> (u32, u32) { from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) } +pub fn watchos_llvm_target(arch: Arch) -> String { + let (major, minor) = watchos_deployment_target(); + format!("{}-apple-watchos{}.{}.0", arch.target_name(), major, minor) +} + pub fn watchos_sim_llvm_target(arch: Arch) -> String { let (major, minor) = watchos_deployment_target(); format!("{}-apple-watchos{}.{}.0-simulator", arch.target_name(), major, minor) diff --git a/compiler/rustc_target/src/spec/base/msvc.rs b/compiler/rustc_target/src/spec/base/msvc.rs index efe949a4e90..44fc376fea0 100644 --- a/compiler/rustc_target/src/spec/base/msvc.rs +++ b/compiler/rustc_target/src/spec/base/msvc.rs @@ -14,6 +14,7 @@ pub fn opts() -> TargetOptions { pre_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, + archive_format: "coff".into(), // Currently this is the only supported method of debuginfo on MSVC // where `*.pdb` files show up next to the final artifact. diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs index 9bf09b4376d..f842a834c05 100644 --- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs +++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs @@ -1,10 +1,11 @@ -use crate::spec::base::apple::{opts, Arch}; +use crate::spec::base::apple::{opts, watchos_llvm_target, Arch}; use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { - let base = opts("watchos", Arch::Arm64_32); + let arch = Arch::Arm64_32; + let base = opts("watchos", arch); Target { - llvm_target: "arm64_32-apple-watchos".into(), + llvm_target: watchos_llvm_target(arch).into(), metadata: crate::spec::TargetMetadata { description: None, tier: None, diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs index 7056288e758..0595e82b39e 100644 --- a/compiler/rustc_trait_selection/src/infer.rs +++ b/compiler/rustc_trait_selection/src/infer.rs @@ -1,5 +1,5 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _; -use crate::traits::{self, DefiningAnchor, ObligationCtxt, SelectionContext}; +use crate::traits::{self, ObligationCtxt, SelectionContext}; use crate::traits::TraitEngineExt as _; use rustc_hir::def_id::DefId; @@ -132,9 +132,8 @@ impl<'tcx> InferCtxtBuilder<'tcx> { R: Debug + TypeFoldable<TyCtxt<'tcx>>, Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>, { - let (infcx, key, canonical_inference_vars) = self - .with_opaque_type_inference(DefiningAnchor::Bubble) - .build_with_canonical(DUMMY_SP, canonical_key); + let (infcx, key, canonical_inference_vars) = + self.build_with_canonical(DUMMY_SP, canonical_key); let ocx = ObligationCtxt::new(&infcx); let value = operation(&ocx, key)?; ocx.make_canonicalized_query_response(canonical_inference_vars, value) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 35f7d1d7151..8b5c029428c 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -363,6 +363,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -596,6 +597,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -684,6 +686,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 00cd4b48797..a778414d9d1 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -50,7 +50,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( Ok(vec![ty::Binder::dummy(element_ty)]) } - ty::Array(element_ty, _) | ty::Slice(element_ty) => Ok(vec![ty::Binder::dummy(element_ty)]), + ty::Pat(element_ty, _) | ty::Array(element_ty, _) | ty::Slice(element_ty) => { + Ok(vec![ty::Binder::dummy(element_ty)]) + } ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet @@ -114,6 +116,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( | ty::Coroutine(..) | ty::CoroutineWitness(..) | ty::Array(..) + | ty::Pat(..) | ty::Closure(..) | ty::CoroutineClosure(..) | ty::Never @@ -177,6 +180,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( | ty::Ref(_, _, Mutability::Not) | ty::Array(..) => Err(NoSolution), + // Cannot implement in core, as we can't be generic over patterns yet, + // so we'd have to list all patterns and type combinations. + ty::Pat(ty, ..) => Ok(vec![ty::Binder::dummy(ty)]), + ty::Dynamic(..) | ty::Str | ty::Slice(_) @@ -285,7 +292,9 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( let kind_ty = args.kind_ty(); let sig = args.coroutine_closure_sig().skip_binder(); - let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() + && !args.tupled_upvars_ty().is_ty_var() + { if !closure_kind.extends(goal_kind) { return Err(NoSolution); } @@ -347,6 +356,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( | ty::CoroutineWitness(..) | ty::Never | ty::Tuple(_) + | ty::Pat(_, _) | ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) @@ -393,7 +403,9 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc let kind_ty = args.kind_ty(); let sig = args.coroutine_closure_sig().skip_binder(); let mut nested = vec![]; - let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() + && !args.tupled_upvars_ty().is_ty_var() + { if !closure_kind.extends(goal_kind) { return Err(NoSolution); } @@ -526,6 +538,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 4a4efb6884f..0b37163d597 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -68,7 +68,6 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { &mut orig_values, QueryInput { goal, - anchor: self.infcx.defining_use_anchor, predefined_opaques_in_body: self .tcx() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 1739bd70e7b..0154aff12b6 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -1,5 +1,5 @@ use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_hir::def_id::{DefId, LocalDefId}; +use rustc_hir::def_id::DefId; use rustc_infer::infer::at::ToTrace; use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; @@ -230,7 +230,6 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { .infer_ctxt() .intercrate(intercrate) .with_next_trait_solver(true) - .with_opaque_type_inference(canonical_input.value.anchor) .build_with_canonical(DUMMY_SP, &canonical_input); let mut ecx = EvalCtxt { @@ -936,8 +935,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { } } - pub(super) fn can_define_opaque_ty(&self, def_id: LocalDefId) -> bool { - self.infcx.opaque_type_origin(def_id).is_some() + 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 insert_hidden_type( diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 8294a8a67b1..da5cd15a10d 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -316,5 +316,6 @@ fn response_no_constraints_raw<'tcx>( external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), certainty, }, + defining_opaque_types: Default::default(), } } diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index fb296d55100..ebf2a0d9621 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -487,6 +487,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { bug!(); }; + // Bail if the upvars haven't been constrained. + if tupled_upvars_ty.expect_ty().is_ty_var() { + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS); + } + let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else { // We don't need to worry about the self type being an infer var. return Err(NoSolution); @@ -533,6 +538,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Uint(..) | ty::Float(..) | ty::Array(..) + | ty::Pat(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) @@ -768,6 +774,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Uint(..) | ty::Float(..) | ty::Array(..) + | ty::Pat(..) | ty::RawPtr(..) | ty::Ref(..) | ty::FnDef(..) diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index eb3ad0aa782..e522339358a 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -155,10 +155,7 @@ 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) - || opaque_ty - .def_id - .as_local() - .is_some_and(|def_id| ecx.can_define_opaque_ty(def_id)) + || ecx.can_define_opaque_ty(opaque_ty.def_id) { return Err(NoSolution); } @@ -1051,6 +1048,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Float(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 8625ad378f7..77eaa4fd03e 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -883,6 +883,7 @@ where | ty::Float(..) | ty::Str | ty::FnDef(..) + | ty::Pat(..) | ty::FnPtr(_) | ty::Array(..) | ty::Slice(..) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 10c03387a5b..837b784f272 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -40,7 +40,7 @@ pub struct ImplCandidate<'tcx> { enum GetSafeTransmuteErrorAndReason { Silent, - Error { err_msg: String, safe_transmute_explanation: String }, + Error { err_msg: String, safe_transmute_explanation: Option<String> }, } struct UnsatisfiedConst(pub bool); 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 af90372b97c..2067956d0f5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1592,8 +1592,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { .tcx .sess .source_map() - .span_extend_while(expr_span, char::is_whitespace) - .unwrap_or(expr_span) + .span_extend_while_whitespace(expr_span) .shrink_to_hi() .to(await_expr.span.shrink_to_hi()); err.span_suggestion( @@ -4851,10 +4850,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( let hir::IsAsync::Async(async_span) = sig.header.asyncness else { return None; }; - let Ok(async_span) = tcx.sess.source_map().span_extend_while(async_span, |c| c.is_whitespace()) - else { - return None; - }; + let async_span = tcx.sess.source_map().span_extend_while_whitespace(async_span); let future = tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty(); let [hir::GenericBound::Trait(trait_ref, _)] = future.bounds else { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 144971b63c0..1b8b09ddda1 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -558,7 +558,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation, - } => (err_msg, Some(safe_transmute_explanation)), + } => (err_msg, safe_transmute_explanation), } } else { (err_msg, None) @@ -1804,6 +1804,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ty::Foreign(..) => Some(19), ty::CoroutineWitness(..) => Some(20), ty::CoroutineClosure(..) => Some(21), + ty::Pat(..) => Some(22), ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None, } } @@ -3067,28 +3068,33 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { return GetSafeTransmuteErrorAndReason::Silent; }; + let dst = trait_ref.args.type_at(0); + let src = trait_ref.args.type_at(1); + let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); + match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( obligation.cause, src_and_dst, assume, ) { Answer::No(reason) => { - let dst = trait_ref.args.type_at(0); - let src = trait_ref.args.type_at(1); - let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); let safe_transmute_explanation = match reason { rustc_transmute::Reason::SrcIsNotYetSupported => { - format!("analyzing the transmutability of `{src}` is not yet supported.") + format!("analyzing the transmutability of `{src}` is not yet supported") } rustc_transmute::Reason::DstIsNotYetSupported => { - format!("analyzing the transmutability of `{dst}` is not yet supported.") + format!("analyzing the transmutability of `{dst}` is not yet supported") } rustc_transmute::Reason::DstIsBitIncompatible => { format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`") } + rustc_transmute::Reason::DstUninhabited => { + format!("`{dst}` is uninhabited") + } + rustc_transmute::Reason::DstMayHaveSafetyInvariants => { format!("`{dst}` may carry safety invariants") } @@ -3134,14 +3140,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { format!("`{dst}` has an unknown layout") } }; - GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation } + GetSafeTransmuteErrorAndReason::Error { + err_msg, + safe_transmute_explanation: Some(safe_transmute_explanation), + } } // Should never get a Yes at this point! We already ran it before, and did not get a Yes. Answer::Yes => span_bug!( span, "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", ), - other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"), + // Reached when a different obligation (namely `Freeze`) causes the + // transmutability analysis to fail. In this case, silence the + // transmutability error message in favor of that more specific + // error. + Answer::If(_) => { + GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None } + } } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 2c8116b779b..98d5b466cd0 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -119,7 +119,9 @@ pub fn predicates_for_generics<'tcx>( /// Determines whether the type `ty` is known to meet `bound` and /// returns true if so. Returns false if `ty` either does not meet -/// `bound` or is not known to meet bound. +/// `bound` or is not known to meet bound (note that this is +/// conservative towards *no impl*, which is the opposite of the +/// `evaluate` methods). pub fn type_known_to_meet_bound_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -127,8 +129,50 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( def_id: DefId, ) -> bool { let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]); - let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, trait_ref); - infcx.predicate_must_hold_modulo_regions(&obligation) + pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref) +} + +/// FIXME(@lcnr): this function doesn't seem right and shouldn't exist? +/// +/// Ping me on zulip if you want to use this method and need help with finding +/// an appropriate replacement. +#[instrument(level = "debug", skip(infcx, param_env, pred), ret)] +fn pred_known_to_hold_modulo_regions<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + pred: impl ToPredicate<'tcx>, +) -> bool { + let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); + + let result = infcx.evaluate_obligation_no_overflow(&obligation); + debug!(?result); + + if result.must_apply_modulo_regions() { + true + } else if result.may_apply() { + // Sometimes obligations are ambiguous because the recursive evaluator + // is not smart enough, so we fall back to fulfillment when we're not certain + // that an obligation holds or not. Even still, we must make sure that + // the we do no inference in the process of checking this obligation. + let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + infcx.probe(|_| { + let ocx = ObligationCtxt::new(infcx); + ocx.register_obligation(obligation); + + let errors = ocx.select_all_or_error(); + match errors.as_slice() { + // Only known to hold if we did no inference. + [] => infcx.shallow_resolve(goal) == goal, + + errors => { + debug!(?errors); + false + } + } + }) + } else { + false + } } #[instrument(level = "debug", skip(tcx, elaborated_env))] diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 9246a41a2bc..a5483c5bbc0 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -793,6 +793,9 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let Some(clause) = clause.as_projection_clause() else { return ControlFlow::Continue(()); }; + if clause.projection_def_id() != obligation.predicate.def_id { + return ControlFlow::Continue(()); + } let is_match = selcx.infcx.probe(|_| selcx.match_projection_projections(obligation, clause, true)); @@ -1045,6 +1048,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Foreign(_) | ty::Str | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::RawPtr(..) | ty::Ref(..) @@ -1096,6 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Float(_) | ty::Str | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::RawPtr(..) | ty::Ref(..) @@ -1596,7 +1601,10 @@ fn confirm_closure_candidate<'cx, 'tcx>( // If we know the kind and upvars, use that directly. // Otherwise, defer to `AsyncFnKindHelper::Upvars` to delay // the projection, like the `AsyncFn*` traits do. - let output_ty = if let Some(_) = kind_ty.to_opt_closure_kind() { + let output_ty = if let Some(_) = kind_ty.to_opt_closure_kind() + // Fall back to projection if upvars aren't constrained + && !args.tupled_upvars_ty().is_ty_var() + { sig.to_coroutine_given_kind_and_upvars( tcx, args.parent_args(), @@ -1726,7 +1734,10 @@ fn confirm_async_closure_candidate<'cx, 'tcx>( let term = match item_name { sym::CallOnceFuture | sym::CallRefFuture => { - if let Some(closure_kind) = kind_ty.to_opt_closure_kind() { + if let Some(closure_kind) = kind_ty.to_opt_closure_kind() + // Fall back to projection if upvars aren't constrained + && !args.tupled_upvars_ty().is_ty_var() + { if !closure_kind.extends(goal_kind) { bug!("we should not be confirming if the closure kind is not met"); } diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index aaa38d14d6e..326c68e01db 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -42,8 +42,8 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Foreign(..) | ty::Error(_) => true, - // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty), + // `T is PAT`, `[T; N]`, and `[T]` have same properties as T. + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, *ty), // (T1..Tn) and closures have same properties as T1..Tn -- // check if *all* of them are trivial. @@ -222,7 +222,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>( // these types never have a destructor } - ty::Array(ety, _) | ty::Slice(ety) => { + ty::Pat(ety, _) | ty::Array(ety, _) | ty::Slice(ety) => { // single-element containers, behave like their element rustc_data_structures::stack::ensure_sufficient_stack(|| { dtorck_constraint_for_ty_inner(tcx, param_env, span, depth + 1, *ety, constraints) diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index faf218131b8..ae4cdb9258e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -159,53 +159,70 @@ where .0); } + let mut error_info = None; let mut region_constraints = QueryRegionConstraints::default(); - let (output, error_info, mut obligations, _) = - Q::fully_perform_into(self, infcx, &mut region_constraints, span).map_err(|_| { - infcx.dcx().span_delayed_bug(span, format!("error performing {self:?}")) - })?; - - // Typically, instantiating NLL query results does not - // create obligations. However, in some cases there - // are unresolved type variables, and unify them *can* - // create obligations. In that case, we have to go - // fulfill them. We do this via a (recursive) query. - while !obligations.is_empty() { - trace!("{:#?}", obligations); - let mut progress = false; - for obligation in std::mem::take(&mut obligations) { - let obligation = infcx.resolve_vars_if_possible(obligation); - match ProvePredicate::fully_perform_into( - obligation.param_env.and(ProvePredicate::new(obligation.predicate)), - infcx, - &mut region_constraints, - span, - ) { - Ok(((), _, new, certainty)) => { - obligations.extend(new); - progress = true; - if let Certainty::Ambiguous = certainty { - obligations.push(obligation); + + // HACK(type_alias_impl_trait): When moving an opaque type to hidden type mapping from the query to the current inferctxt, + // we sometimes end up with `Opaque<'a> = Opaque<'b>` instead of an actual hidden type. In that case we don't register a + // hidden type but just equate the lifetimes. Thus we need to scrape the region constraints even though we're also manually + // collecting region constraints via `region_constraints`. + let (mut output, _) = scrape_region_constraints( + infcx, + |_ocx| { + let (output, ei, mut obligations, _) = + Q::fully_perform_into(self, infcx, &mut region_constraints, span)?; + error_info = ei; + + // Typically, instantiating NLL query results does not + // create obligations. However, in some cases there + // are unresolved type variables, and unify them *can* + // create obligations. In that case, we have to go + // fulfill them. We do this via a (recursive) query. + while !obligations.is_empty() { + trace!("{:#?}", obligations); + let mut progress = false; + for obligation in std::mem::take(&mut obligations) { + let obligation = infcx.resolve_vars_if_possible(obligation); + match ProvePredicate::fully_perform_into( + obligation.param_env.and(ProvePredicate::new(obligation.predicate)), + infcx, + &mut region_constraints, + span, + ) { + Ok(((), _, new, certainty)) => { + obligations.extend(new); + progress = true; + if let Certainty::Ambiguous = certainty { + obligations.push(obligation); + } + } + Err(_) => obligations.push(obligation), } } - Err(_) => obligations.push(obligation), + if !progress { + infcx.dcx().span_bug( + span, + format!("ambiguity processing {obligations:?} from {self:?}"), + ); + } } - } - if !progress { - infcx - .dcx() - .span_bug(span, format!("ambiguity processing {obligations:?} from {self:?}")); - } - } - - Ok(TypeOpOutput { - output, - constraints: if region_constraints.is_empty() { - None - } else { - Some(infcx.tcx.arena.alloc(region_constraints)) + Ok(output) }, - error_info, - }) + "fully_perform", + span, + )?; + output.error_info = error_info; + if let Some(constraints) = output.constraints { + region_constraints + .member_constraints + .extend(constraints.member_constraints.iter().cloned()); + region_constraints.outlives.extend(constraints.outlives.iter().cloned()); + } + output.constraints = if region_constraints.is_empty() { + None + } else { + Some(infcx.tcx.arena.alloc(region_constraints)) + }; + Ok(output) } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index c6ea596b819..974e5ef0e16 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -400,39 +400,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } ty::CoroutineClosure(def_id, args) => { + let args = args.as_coroutine_closure(); let is_const = self.tcx().is_const_fn_raw(def_id); - match self.infcx.closure_kind(self_ty) { - Some(closure_kind) => { - let no_borrows = match self - .infcx - .shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty()) - .kind() - { - ty::Tuple(tys) => tys.is_empty(), - ty::Error(_) => false, - _ => bug!("tuple_fields called on non-tuple"), - }; - // A coroutine-closure implements `FnOnce` *always*, since it may - // always be called once. It additionally implements `Fn`/`FnMut` - // only if it has no upvars (therefore no borrows from the closure - // that would need to be represented with a lifetime) and if the - // closure kind permits it. - // FIXME(async_closures): Actually, it could also implement `Fn`/`FnMut` - // if it takes all of its upvars by copy, and none by ref. This would - // require us to record a bit more information during upvar analysis. - if no_borrows && closure_kind.extends(kind) { - candidates.vec.push(ClosureCandidate { is_const }); - } else if kind == ty::ClosureKind::FnOnce { - candidates.vec.push(ClosureCandidate { is_const }); - } + if let Some(closure_kind) = self.infcx.closure_kind(self_ty) + // Ambiguity if upvars haven't been constrained yet + && !args.tupled_upvars_ty().is_ty_var() + { + let no_borrows = match args.tupled_upvars_ty().kind() { + ty::Tuple(tys) => tys.is_empty(), + ty::Error(_) => false, + _ => bug!("tuple_fields called on non-tuple"), + }; + // A coroutine-closure implements `FnOnce` *always*, since it may + // always be called once. It additionally implements `Fn`/`FnMut` + // only if it has no upvars (therefore no borrows from the closure + // that would need to be represented with a lifetime) and if the + // closure kind permits it. + // FIXME(async_closures): Actually, it could also implement `Fn`/`FnMut` + // if it takes all of its upvars by copy, and none by ref. This would + // require us to record a bit more information during upvar analysis. + if no_borrows && closure_kind.extends(kind) { + candidates.vec.push(ClosureCandidate { is_const }); + } else if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); } - None => { - if kind == ty::ClosureKind::FnOnce { - candidates.vec.push(ClosureCandidate { is_const }); - } else { - // This stays ambiguous until kind+upvars are determined. - candidates.ambiguous = true; - } + } else { + if kind == ty::ClosureKind::FnOnce { + candidates.vec.push(ClosureCandidate { is_const }); + } else { + // This stays ambiguous until kind+upvars are determined. + candidates.ambiguous = true; } } } @@ -670,6 +667,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(_, _, _) @@ -803,6 +801,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Float(_) | ty::Str | ty::Array(_, _) + | ty::Pat(_, _) | ty::Slice(_) | ty::Adt(..) | ty::RawPtr(_, _) @@ -1193,6 +1192,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Never | ty::Foreign(_) | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::Closure(..) | ty::CoroutineClosure(..) @@ -1270,6 +1270,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::RawPtr(_, _) | ty::Ref(_, _, _) | ty::FnDef(_, _) + | ty::Pat(_, _) | ty::FnPtr(_) | ty::Dynamic(_, _, _) | ty::Closure(..) @@ -1329,6 +1330,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | ty::Foreign(..) | ty::Str | ty::Array(..) + | ty::Pat(..) | ty::Slice(_) | ty::RawPtr(_, _) | ty::Ref(..) diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0459246553b..25ba985397e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -314,12 +314,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .flat_map(|cond| flatten_answer_tree(tcx, obligation, predicate, cond)) .collect(), Condition::IfTransmutable { src, dst } => { - let trait_def_id = obligation.predicate.def_id(); + let transmute_trait = obligation.predicate.def_id(); let assume_const = predicate.trait_ref.args.const_at(2); - let make_obl = |from_ty, to_ty| { - let trait_ref1 = ty::TraitRef::new( + let make_transmute_obl = |from_ty, to_ty| { + let trait_ref = ty::TraitRef::new( tcx, - trait_def_id, + transmute_trait, [ ty::GenericArg::from(to_ty), ty::GenericArg::from(from_ty), @@ -331,17 +331,45 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, - trait_ref1, + trait_ref, ) }; + let make_freeze_obl = |ty| { + let trait_ref = ty::TraitRef::new( + tcx, + tcx.lang_items().freeze_trait().unwrap(), + [ty::GenericArg::from(ty)], + ); + Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + trait_ref, + ) + }; + + let mut obls = vec![]; + + // If the source is a shared reference, it must be `Freeze`; + // otherwise, transmuting could lead to data races. + if src.mutability == Mutability::Not { + obls.extend([make_freeze_obl(src.ty), make_freeze_obl(dst.ty)]) + } + // If Dst is mutable, check bidirectionally. // For example, transmuting bool -> u8 is OK as long as you can't update that u8 // to be > 1, because you could later transmute the u8 back to a bool and get UB. match dst.mutability { - Mutability::Not => vec![make_obl(src.ty, dst.ty)], - Mutability::Mut => vec![make_obl(src.ty, dst.ty), make_obl(dst.ty, src.ty)], + Mutability::Not => obls.push(make_transmute_obl(src.ty, dst.ty)), + Mutability::Mut => obls.extend([ + make_transmute_obl(src.ty, dst.ty), + make_transmute_obl(dst.ty, src.ty), + ]), } + + obls } } } @@ -1417,7 +1445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // These types are built-in, so we can fast-track by registering // nested predicates for their constituent type(s) - ty::Array(ty, _) | ty::Slice(ty) => { + ty::Array(ty, _) | ty::Slice(ty) | ty::Pat(ty, _) => { stack.push(ty); } ty::Tuple(tys) => { @@ -1469,7 +1497,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If we have any other type (e.g. an ADT), just register a nested obligation // since it's either not `const Drop` (and we raise an error during selection), // or it's an ADT (and we need to check for a custom impl during selection) - _ => { + ty::Error(_) + | ty::Dynamic(..) + | ty::CoroutineClosure(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Adt(..) + | ty::Alias(ty::Opaque | ty::Weak, _) + | ty::Infer(_) + | ty::Placeholder(_) => { let predicate = self_ty.rebind(ty::TraitPredicate { trait_ref: ty::TraitRef::from_lang_item( self.tcx(), diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index aa4ab9c7ee9..e363119393a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1732,6 +1732,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { env_predicate: PolyProjectionPredicate<'tcx>, potentially_unnormalized_candidates: bool, ) -> ProjectionMatchesProjection { + debug_assert_eq!(obligation.predicate.def_id, env_predicate.projection_def_id()); + let mut nested_obligations = Vec::new(); let infer_predicate = self.infcx.instantiate_binder_with_fresh_vars( obligation.cause.span, @@ -2140,6 +2142,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])), ), + ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])), + ty::Adt(def, args) => { if let Some(sized_crit) = def.sized_constraint(self.tcx()) { // (*) binder moved here @@ -2200,6 +2204,11 @@ impl<'tcx> SelectionContext<'_, 'tcx> { Where(obligation.predicate.rebind(tys.iter().collect())) } + ty::Pat(ty, _) => { + // (*) binder moved here + Where(obligation.predicate.rebind(vec![ty])) + } + ty::Coroutine(coroutine_def_id, args) => { match self.tcx().coroutine_movability(coroutine_def_id) { hir::Movability::Static => None, @@ -2338,7 +2347,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> { ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => t.rebind(vec![element_ty]), - ty::Array(element_ty, _) | ty::Slice(element_ty) => t.rebind(vec![element_ty]), + ty::Pat(ty, _) | ty::Array(ty, _) | ty::Slice(ty) => t.rebind(vec![ty]), ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs index b89406ca023..6778ac81aea 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -126,7 +126,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> { return ControlFlow::Continue(()); } - ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { + ty::Pat(..) | ty::Array(..) | ty::Slice(_) | ty::Ref(..) | ty::Tuple(..) => { // First check all contained types and then tell the caller to continue searching. return ty.super_visit_with(self); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index a44a5ae0e6b..5553490542b 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -681,6 +681,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> { // Note that we handle the len is implicitly checked while walking `arg`. } + ty::Pat(subty, _) => { + self.require_sized(subty, traits::MiscObligation); + } + ty::Tuple(tys) => { if let Some((_last, rest)) = tys.split_last() { for &elem in rest { diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index b8922696e30..77d5a48f158 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -35,6 +35,7 @@ impl<R> Transitions<R> where R: Ref, { + #[allow(dead_code)] fn insert(&mut self, transition: Transition<R>, state: State) { match transition { Transition::Byte(b) => { @@ -82,6 +83,7 @@ impl<R> Dfa<R> where R: Ref, { + #[allow(dead_code)] pub(crate) fn unit() -> Self { let transitions: Map<State, Transitions<R>> = Map::default(); let start = State::new(); diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs index 78fcceb5f2c..3c5963202c6 100644 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -160,6 +160,7 @@ where Self { transitions, start, accepting } } + #[allow(dead_code)] pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> { self.transitions.get(&start) } diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index f6bc224c7e7..12c984f1603 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -173,16 +173,20 @@ pub(crate) mod rustc { use super::Tree; use crate::layout::rustc::{Def, Ref}; + use rustc_middle::ty::layout::HasTyCtxt; + use rustc_middle::ty::layout::LayoutCx; use rustc_middle::ty::layout::LayoutError; + use rustc_middle::ty::layout::LayoutOf; use rustc_middle::ty::AdtDef; - use rustc_middle::ty::GenericArgsRef; - use rustc_middle::ty::ParamEnv; + use rustc_middle::ty::AdtKind; + use rustc_middle::ty::List; use rustc_middle::ty::ScalarInt; - use rustc_middle::ty::VariantDef; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::ErrorGuaranteed; - use rustc_target::abi::Align; - use std::alloc; + use rustc_target::abi::FieldsShape; + use rustc_target::abi::Size; + use rustc_target::abi::TyAndLayout; + use rustc_target::abi::Variants; #[derive(Debug, Copy, Clone)] pub(crate) enum Err { @@ -206,176 +210,64 @@ pub(crate) mod rustc { } } - trait LayoutExt { - fn clamp_align(&self, min_align: Align, max_align: Align) -> Self; - } - - impl LayoutExt for alloc::Layout { - fn clamp_align(&self, min_align: Align, max_align: Align) -> Self { - let min_align = min_align.bytes().try_into().unwrap(); - let max_align = max_align.bytes().try_into().unwrap(); - Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap() - } - } - - struct LayoutSummary { - total_align: Align, - total_size: usize, - discriminant_size: usize, - discriminant_align: Align, - } - - impl LayoutSummary { - fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> { - use rustc_middle::ty::ParamEnvAnd; - use rustc_target::abi::{TyAndLayout, Variants}; - - let param_env = ParamEnv::reveal_all(); - let param_env_and_type = ParamEnvAnd { param_env, value: ty }; - let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; - - let total_size: usize = layout.size().bytes_usize(); - let total_align: Align = layout.align().abi; - let discriminant_align: Align; - let discriminant_size: usize; - - if let Variants::Multiple { tag, .. } = layout.variants() { - discriminant_align = tag.align(&ctx).abi; - discriminant_size = tag.size(&ctx).bytes_usize(); - } else { - discriminant_align = Align::ONE; - discriminant_size = 0; - }; - - Ok(Self { total_align, total_size, discriminant_align, discriminant_size }) - } - - fn into(&self) -> alloc::Layout { - alloc::Layout::from_size_align( - self.total_size, - self.total_align.bytes().try_into().unwrap(), - ) - .unwrap() - } - } - impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> { - pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> { - use rustc_middle::ty::FloatTy::*; - use rustc_middle::ty::IntTy::*; - use rustc_middle::ty::UintTy::*; + pub fn from_ty( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { use rustc_target::abi::HasDataLayout; - if let Err(e) = ty.error_reported() { + if let Err(e) = ty_and_layout.ty.error_reported() { return Err(Err::TypeError(e)); } - let target = tcx.data_layout(); + let target = cx.tcx.data_layout(); + let pointer_size = target.pointer_size; - match ty.kind() { + match ty_and_layout.ty.kind() { ty::Bool => Ok(Self::bool()), - ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()), - ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)), - ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)), - ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)), - ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)), - ty::Int(Isize) | ty::Uint(Usize) => { - Ok(Self::number(target.pointer_size.bytes_usize())) + ty::Float(nty) => { + let width = nty.bit_width() / 8; + Ok(Self::number(width as _)) } - ty::Tuple(members) => { - if members.len() == 0 { - Ok(Tree::unit()) - } else { - Err(Err::NotYetSupported) - } + ty::Int(nty) => { + let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8; + Ok(Self::number(width as _)) } - ty::Array(ty, len) => { - let len = len - .try_eval_target_usize(tcx, ParamEnv::reveal_all()) - .ok_or(Err::NotYetSupported)?; - let elt = Tree::from_ty(*ty, tcx)?; - Ok(std::iter::repeat(elt) - .take(len as usize) - .fold(Tree::unit(), |tree, elt| tree.then(elt))) + ty::Uint(nty) => { + let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8; + Ok(Self::number(width as _)) } - ty::Adt(adt_def, args_ref) => { - use rustc_middle::ty::AdtKind; + ty::Tuple(members) => Self::from_tuple(ty_and_layout, members, cx), - // If the layout is ill-specified, halt. - if !(adt_def.repr().c() || adt_def.repr().int.is_some()) { + ty::Array(inner_ty, len) => { + let FieldsShape::Array { stride, count } = &ty_and_layout.fields else { return Err(Err::NotYetSupported); - } + }; + let inner_ty_and_layout = cx.layout_of(*inner_ty)?; + assert_eq!(*stride, inner_ty_and_layout.size); + let elt = Tree::from_ty(inner_ty_and_layout, cx)?; + Ok(std::iter::repeat(elt) + .take(*count as usize) + .fold(Tree::unit(), |tree, elt| tree.then(elt))) + } - // Compute a summary of the type's layout. - let layout_summary = LayoutSummary::from_ty(ty, tcx)?; - - // The layout begins with this adt's visibility. - let vis = Self::def(Def::Adt(*adt_def)); - - // And is followed the layout(s) of its variants - Ok(vis.then(match adt_def.adt_kind() { - AdtKind::Struct => Self::from_repr_c_variant( - ty, - *adt_def, - args_ref, - &layout_summary, - None, - adt_def.non_enum_variant(), - tcx, - )?, - AdtKind::Enum => { - trace!(?adt_def, "treeifying enum"); - let mut tree = Tree::uninhabited(); - - for (idx, variant) in adt_def.variants().iter_enumerated() { - let tag = tcx.tag_for_variant((ty, idx)); - tree = tree.or(Self::from_repr_c_variant( - ty, - *adt_def, - args_ref, - &layout_summary, - tag, - variant, - tcx, - )?); - } - - tree - } - AdtKind::Union => { - // is the layout well-defined? - if !adt_def.repr().c() { - return Err(Err::NotYetSupported); - } - - let ty_layout = layout_of(tcx, ty)?; - - let mut tree = Tree::uninhabited(); - - for field in adt_def.all_fields() { - let variant_ty = field.ty(tcx, args_ref); - let variant_layout = layout_of(tcx, variant_ty)?; - let padding_needed = ty_layout.size() - variant_layout.size(); - let variant = Self::def(Def::Field(field)) - .then(Self::from_ty(variant_ty, tcx)?) - .then(Self::padding(padding_needed)); - - tree = tree.or(variant); - } - - tree - } - })) + ty::Adt(adt_def, _args_ref) if !ty_and_layout.ty.is_box() => { + match adt_def.adt_kind() { + AdtKind::Struct => Self::from_struct(ty_and_layout, *adt_def, cx), + AdtKind::Enum => Self::from_enum(ty_and_layout, *adt_def, cx), + AdtKind::Union => Self::from_union(ty_and_layout, *adt_def, cx), + } } ty::Ref(lifetime, ty, mutability) => { - let layout = layout_of(tcx, *ty)?; - let align = layout.align(); - let size = layout.size(); + let ty_and_layout = cx.layout_of(*ty)?; + let align = ty_and_layout.align.abi.bytes() as usize; + let size = ty_and_layout.size.bytes_usize(); Ok(Tree::Ref(Ref { lifetime: *lifetime, ty: *ty, @@ -389,80 +281,143 @@ pub(crate) mod rustc { } } - fn from_repr_c_variant( - ty: Ty<'tcx>, - adt_def: AdtDef<'tcx>, - args_ref: GenericArgsRef<'tcx>, - layout_summary: &LayoutSummary, - tag: Option<ScalarInt>, - variant_def: &'tcx VariantDef, - tcx: TyCtxt<'tcx>, + /// Constructs a `Tree` from a tuple. + fn from_tuple( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + members: &'tcx List<Ty<'tcx>>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, ) -> Result<Self, Err> { - let mut tree = Tree::unit(); - - let repr = adt_def.repr(); - let min_align = repr.align.unwrap_or(Align::ONE); - let max_align = repr.pack.unwrap_or(Align::MAX); - - let variant_span = trace_span!( - "treeifying variant", - min_align = ?min_align, - max_align = ?max_align, - ) - .entered(); - - let mut variant_layout = alloc::Layout::from_size_align( - 0, - layout_summary.total_align.bytes().try_into().unwrap(), - ) - .unwrap(); - - // The layout of the variant is prefixed by the tag, if any. - if let Some(tag) = tag { - let tag_layout = - alloc::Layout::from_size_align(tag.size().bytes_usize(), 1).unwrap(); - tree = tree.then(Self::from_tag(tag, tcx)); - variant_layout = variant_layout.extend(tag_layout).unwrap().0; + match &ty_and_layout.fields { + FieldsShape::Primitive => { + assert_eq!(members.len(), 1); + let inner_ty = members[0]; + let inner_ty_and_layout = cx.layout_of(inner_ty)?; + assert_eq!(ty_and_layout.layout, inner_ty_and_layout.layout); + Self::from_ty(inner_ty_and_layout, cx) + } + FieldsShape::Arbitrary { offsets, .. } => { + assert_eq!(offsets.len(), members.len()); + Self::from_variant(Def::Primitive, None, ty_and_layout, ty_and_layout.size, cx) + } + FieldsShape::Array { .. } | FieldsShape::Union(_) => Err(Err::NotYetSupported), + } + } + + /// Constructs a `Tree` from a struct. + /// + /// # Panics + /// + /// Panics if `def` is not a struct definition. + fn from_struct( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + def: AdtDef<'tcx>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + assert!(def.is_struct()); + let def = Def::Adt(def); + Self::from_variant(def, None, ty_and_layout, ty_and_layout.size, cx) + } + + /// Constructs a `Tree` from an enum. + /// + /// # Panics + /// + /// Panics if `def` is not an enum definition. + fn from_enum( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + def: AdtDef<'tcx>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + assert!(def.is_enum()); + let layout = ty_and_layout.layout; + + if let Variants::Multiple { tag_field, .. } = layout.variants() { + // For enums (but not coroutines), the tag field is + // currently always the first field of the layout. + assert_eq!(*tag_field, 0); } - // Next come fields. - let fields_span = trace_span!("treeifying fields").entered(); - for field_def in variant_def.fields.iter() { - let field_ty = field_def.ty(tcx, args_ref); - let _span = trace_span!("treeifying field", field = ?field_ty).entered(); + let variants = def.discriminants(cx.tcx()).try_fold( + Self::uninhabited(), + |variants, (idx, ref discriminant)| { + let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, idx)); + let variant_def = Def::Variant(def.variant(idx)); + let variant_ty_and_layout = ty_and_layout.for_variant(&cx, idx); + let variant = Self::from_variant( + variant_def, + tag, + variant_ty_and_layout, + layout.size, + cx, + )?; + Result::<Self, Err>::Ok(variants.or(variant)) + }, + )?; - // begin with the field's visibility - tree = tree.then(Self::def(Def::Field(field_def))); + return Ok(Self::def(Def::Adt(def)).then(variants)); + } - // compute the field's layout characteristics - let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align); + /// Constructs a `Tree` from a 'variant-like' layout. + /// + /// A 'variant-like' layout includes those of structs and, of course, + /// enum variants. Pragmatically speaking, this method supports anything + /// with `FieldsShape::Arbitrary`. + /// + /// Note: This routine assumes that the optional `tag` is the first + /// field, and enum callers should check that `tag_field` is, in fact, + /// `0`. + fn from_variant( + def: Def<'tcx>, + tag: Option<ScalarInt>, + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + total_size: Size, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + // This constructor does not support non-`FieldsShape::Arbitrary` + // layouts. + let FieldsShape::Arbitrary { offsets, memory_index } = ty_and_layout.layout.fields() + else { + return Err(Err::NotYetSupported); + }; - // next comes the field's padding - let padding_needed = variant_layout.padding_needed_for(field_layout.align()); - if padding_needed > 0 { - tree = tree.then(Self::padding(padding_needed)); - } + // When this function is invoked with enum variants, + // `ty_and_layout.size` does not encompass the entire size of the + // enum. We rely on `total_size` for this. + assert!(ty_and_layout.size <= total_size); - // finally, the field's layout - tree = tree.then(Self::from_ty(field_ty, tcx)?); + let mut size = Size::ZERO; + let mut struct_tree = Self::def(def); - // extend the variant layout with the field layout - variant_layout = variant_layout.extend(field_layout).unwrap().0; + // If a `tag` is provided, place it at the start of the layout. + if let Some(tag) = tag { + size += tag.size(); + struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx)); } - drop(fields_span); - // finally: padding - let padding_span = trace_span!("adding trailing padding").entered(); - if layout_summary.total_size > variant_layout.size() { - let padding_needed = layout_summary.total_size - variant_layout.size(); - tree = tree.then(Self::padding(padding_needed)); - }; - drop(padding_span); - drop(variant_span); - Ok(tree) + // Append the fields, in memory order, to the layout. + let inverse_memory_index = memory_index.invert_bijective_mapping(); + for (memory_idx, field_idx) in inverse_memory_index.iter_enumerated() { + // Add interfield padding. + let padding_needed = offsets[*field_idx] - size; + let padding = Self::padding(padding_needed.bytes_usize()); + + let field_ty_and_layout = ty_and_layout.field(&cx, field_idx.as_usize()); + let field_tree = Self::from_ty(field_ty_and_layout, cx)?; + + struct_tree = struct_tree.then(padding).then(field_tree); + + size += padding_needed + field_ty_and_layout.size; + } + + // Add trailing padding. + let padding_needed = total_size - size; + let trailing_padding = Self::padding(padding_needed.bytes_usize()); + + Ok(struct_tree.then(trailing_padding)) } - pub fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self { + /// Constructs a `Tree` representing the value of a enum tag. + fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self { use rustc_target::abi::Endian; let size = tag.size(); let bits = tag.to_bits(size).unwrap(); @@ -479,24 +434,42 @@ pub(crate) mod rustc { }; Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect()) } - } - fn layout_of<'tcx>( - ctx: TyCtxt<'tcx>, - ty: Ty<'tcx>, - ) -> Result<alloc::Layout, &'tcx LayoutError<'tcx>> { - use rustc_middle::ty::ParamEnvAnd; - use rustc_target::abi::TyAndLayout; - - let param_env = ParamEnv::reveal_all(); - let param_env_and_type = ParamEnvAnd { param_env, value: ty }; - let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; - let layout = alloc::Layout::from_size_align( - layout.size().bytes_usize(), - layout.align().abi.bytes().try_into().unwrap(), - ) - .unwrap(); - trace!(?ty, ?layout, "computed layout for type"); - Ok(layout) + /// Constructs a `Tree` from a union. + /// + /// # Panics + /// + /// Panics if `def` is not a union definition. + fn from_union( + ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>, + def: AdtDef<'tcx>, + cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Result<Self, Err> { + assert!(def.is_union()); + + let union_layout = ty_and_layout.layout; + + // This constructor does not support non-`FieldsShape::Union` + // layouts. Fields of this shape are all placed at offset 0. + let FieldsShape::Union(fields) = union_layout.fields() else { + return Err(Err::NotYetSupported); + }; + + let fields = &def.non_enum_variant().fields; + let fields = fields.iter_enumerated().try_fold( + Self::uninhabited(), + |fields, (idx, ref field_def)| { + let field_def = Def::Field(field_def); + let field_ty_and_layout = ty_and_layout.field(&cx, idx.as_usize()); + let field = Self::from_ty(field_ty_and_layout, cx)?; + let trailing_padding_needed = union_layout.size - field_ty_and_layout.size; + let trailing_padding = Self::padding(trailing_padding_needed.bytes_usize()); + let field_and_padding = field.then(trailing_padding); + Result::<Self, Err>::Ok(fields.or(field_and_padding)) + }, + )?; + + Ok(Self::def(Def::Adt(def)).then(fields)) + } } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index b6f937ebe47..12312271646 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -1,6 +1,6 @@ #![feature(alloc_layout_extra)] #![feature(never_type)] -#![allow(dead_code, unused_variables)] +#![allow(unused_variables)] #[macro_use] extern crate tracing; @@ -49,6 +49,8 @@ pub enum Reason<T> { DstIsNotYetSupported, /// The layout of the destination type is bit-incompatible with the source type. DstIsBitIncompatible, + /// The destination type is uninhabited. + DstUninhabited, /// The destination type may carry safety invariants. DstMayHaveSafetyInvariants, /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized. diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 16d15580a05..2789fe8f6b1 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -33,6 +33,9 @@ mod rustc { use super::*; use crate::layout::tree::rustc::Err; + use rustc_middle::ty::layout::LayoutCx; + use rustc_middle::ty::layout::LayoutOf; + use rustc_middle::ty::ParamEnv; use rustc_middle::ty::Ty; use rustc_middle::ty::TyCtxt; @@ -43,12 +46,20 @@ mod rustc { pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> { let Self { src, dst, assume, context } = self; + let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() }; + let layout_of = |ty| { + layout_cx + .layout_of(ty) + .map_err(|_| Err::NotYetSupported) + .and_then(|tl| Tree::from_ty(tl, layout_cx)) + }; + // Convert `src` and `dst` from their rustc representations, to `Tree`-based // representations. If these conversions fail, conclude that the transmutation is // unacceptable; the layouts of both the source and destination types must be // well-defined. - let src = Tree::from_ty(src, context); - let dst = Tree::from_ty(dst, context); + let src = layout_of(src); + let dst = layout_of(dst); match (src, dst) { (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => { @@ -86,6 +97,10 @@ where // references. let src = src.prune(&|def| false); + if src.is_inhabited() && !dst.is_inhabited() { + return Answer::No(Reason::DstUninhabited); + } + trace!(?src, "pruned src"); // Remove all `Def` nodes from `dst`, additionally... diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 54ed03d44e6..1ccb6f36c8e 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -5,8 +5,6 @@ pub(crate) trait QueryContext { type Def: layout::Def; type Ref: layout::Ref; type Scope: Copy; - - fn min_align(&self, reference: Self::Ref) -> usize; } #[cfg(test)] @@ -31,10 +29,6 @@ pub(crate) mod test { type Def = Def; type Ref = !; type Scope = (); - - fn min_align(&self, reference: !) -> usize { - unimplemented!() - } } } @@ -48,9 +42,5 @@ mod rustc { type Ref = layout::rustc::Ref<'tcx>; type Scope = Ty<'tcx>; - - fn min_align(&self, reference: Self::Ref) -> usize { - unimplemented!() - } } } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 509727cdeab..77cd4662ae5 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -126,6 +126,39 @@ fn layout_of_uncached<'tcx>( debug_assert!(!ty.has_non_region_infer()); Ok(match *ty.kind() { + ty::Pat(ty, pat) => { + let layout = cx.layout_of(ty)?.layout; + let mut layout = LayoutS::clone(&layout.0); + match *pat { + ty::PatternKind::Range { start, end, include_end } => { + if let Abi::Scalar(scalar) | Abi::ScalarPair(scalar, _) = &mut layout.abi { + if let Some(start) = start { + scalar.valid_range_mut().start = start.eval_bits(tcx, param_env); + } + if let Some(end) = end { + let mut end = end.eval_bits(tcx, param_env); + if !include_end { + end = end.wrapping_sub(1); + } + scalar.valid_range_mut().end = end; + } + + let niche = Niche { + offset: Size::ZERO, + value: scalar.primitive(), + valid_range: scalar.valid_range(cx), + }; + + layout.largest_niche = Some(niche); + + tcx.mk_layout(layout) + } else { + bug!("pattern type with range but not scalar layout: {ty:?}, {layout:?}") + } + } + } + } + // Basic scalars. ty::Bool => tcx.mk_layout(LayoutS::scalar( cx, diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index 48339e6120a..ee930a78e77 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -221,6 +221,7 @@ where | ty::Ref(..) | ty::RawPtr(..) | ty::FnDef(..) + | ty::Pat(..) | ty::FnPtr(..) | ty::Tuple(_) | ty::Bound(..) diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 547a3cb5a8c..f33234122c9 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -36,6 +36,8 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<' // these are never sized Str | Slice(..) | Dynamic(_, _, ty::Dyn) | Foreign(..) => Some(ty), + Pat(ty, _) => sized_constraint_for_ty(tcx, *ty), + Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)), // recursive case diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index ad18ef24984..06a5051956a 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -16,6 +16,8 @@ use crate::{Interner, PlaceholderLike, UniverseIndex}; pub struct Canonical<I: Interner, V> { pub value: V, pub max_universe: UniverseIndex, + // FIXME(lcnr, oli-obk): try moving this into the query inputs instead + pub defining_opaque_types: I::DefiningOpaqueTypes, pub variables: I::CanonicalVars, } @@ -44,8 +46,8 @@ impl<I: Interner, V> Canonical<I, V> { /// let b: Canonical<I, (T, Ty<I>)> = a.unchecked_map(|v| (v, ty)); /// ``` pub fn unchecked_map<W>(self, map_op: impl FnOnce(V) -> W) -> Canonical<I, W> { - let Canonical { max_universe, variables, value } = self; - Canonical { max_universe, variables, value: map_op(value) } + let Canonical { defining_opaque_types, max_universe, variables, value } = self; + Canonical { defining_opaque_types, max_universe, variables, value: map_op(value) } } /// Allows you to map the `value` of a canonical while keeping the same set of @@ -54,8 +56,8 @@ impl<I: Interner, V> Canonical<I, V> { /// **WARNING:** This function is very easy to mis-use, hence the name! See /// the comment of [Canonical::unchecked_map] for more details. pub fn unchecked_rebind<W>(self, value: W) -> Canonical<I, W> { - let Canonical { max_universe, variables, value: _ } = self; - Canonical { max_universe, variables, value } + let Canonical { defining_opaque_types, max_universe, variables, value: _ } = self; + Canonical { defining_opaque_types, max_universe, variables, value } } } @@ -63,28 +65,32 @@ impl<I: Interner, V: Eq> Eq for Canonical<I, V> {} impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> { fn eq(&self, other: &Self) -> bool { - self.value == other.value - && self.max_universe == other.max_universe - && self.variables == other.variables + let Self { value, max_universe, variables, defining_opaque_types } = self; + *value == other.value + && *max_universe == other.max_universe + && *variables == other.variables + && *defining_opaque_types == other.defining_opaque_types } } impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { value, max_universe, variables, defining_opaque_types } = self; write!( f, - "Canonical {{ value: {}, max_universe: {:?}, variables: {:?} }}", - self.value, self.max_universe, self.variables + "Canonical {{ value: {value}, max_universe: {max_universe:?}, variables: {variables:?}, defining_opaque_types: {defining_opaque_types:?} }}", ) } } impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self { value, max_universe, variables, defining_opaque_types } = self; f.debug_struct("Canonical") - .field("value", &self.value) - .field("max_universe", &self.max_universe) - .field("variables", &self.variables) + .field("value", &value) + .field("max_universe", &max_universe) + .field("variables", &variables) + .field("defining_opaque_types", &defining_opaque_types) .finish() } } @@ -100,6 +106,7 @@ where value: self.value.try_fold_with(folder)?, max_universe: self.max_universe.try_fold_with(folder)?, variables: self.variables.try_fold_with(folder)?, + defining_opaque_types: self.defining_opaque_types, }) } } @@ -109,9 +116,11 @@ where I::CanonicalVars: TypeVisitable<I>, { fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> F::Result { - try_visit!(self.value.visit_with(folder)); - try_visit!(self.max_universe.visit_with(folder)); - self.variables.visit_with(folder) + let Self { value, max_universe, variables, defining_opaque_types } = self; + try_visit!(value.visit_with(folder)); + try_visit!(max_universe.visit_with(folder)); + try_visit!(defining_opaque_types.visit_with(folder)); + variables.visit_with(folder) } } diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs index 9c8e45b4338..9298360f749 100644 --- a/compiler/rustc_type_ir/src/debug.rs +++ b/compiler/rustc_type_ir/src/debug.rs @@ -43,6 +43,10 @@ impl<I: Interner> InferCtxtLike for NoInfcx<I> { fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> { None } + + fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes { + Default::default() + } } pub trait DebugWithInfcx<I: Interner>: fmt::Debug { diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 28b71f0ea13..a53287c1987 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -37,4 +37,6 @@ pub trait InferCtxtLike { /// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type. fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>; + + fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 7a2885dd3bb..70f7e58be19 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -11,6 +11,7 @@ use crate::{ pub trait Interner: Sized + Copy { type DefId: Copy + Debug + Hash + Eq; + type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>; type AdtDef: Copy + Debug + Hash + Eq; type GenericArgs: Copy @@ -49,6 +50,7 @@ pub trait Interner: Sized + Copy { type BoundExistentialPredicates: Copy + DebugWithInfcx<Self> + Hash + Eq; type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq; type AllocId: Copy + Debug + Hash + Eq; + type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>; // Kinds of consts type Const: Copy @@ -100,6 +102,7 @@ pub trait Interner: Sized + Copy { type SubtypePredicate: Copy + Debug + Hash + Eq; type CoercePredicate: Copy + Debug + Hash + Eq; type ClosureKind: Copy + Debug + Hash + Eq; + type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars; } diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index fad67fe3cbb..8813955f2af 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -100,6 +100,13 @@ pub enum TyKind<I: Interner> { /// An array with the given length. Written as `[T; N]`. Array(I::Ty, I::Const), + /// A pattern newtype. Takes any type and restricts its valid values to its pattern. + /// This will also change the layout to take advantage of this restriction. + /// Only `Copy` and `Clone` will automatically get implemented for pattern types. + /// Auto-traits treat this as if it were an aggregate with a single nested type. + /// Only supports integer range patterns for now. + Pat(I::Ty, I::Pat), + /// The pointee of an array slice. Written as `[T]`. Slice(I::Ty), @@ -273,12 +280,13 @@ const fn tykind_discriminant<I: Interner>(value: &TyKind<I>) -> usize { CoroutineWitness(_, _) => 18, Never => 19, Tuple(_) => 20, - Alias(_, _) => 21, - Param(_) => 22, - Bound(_, _) => 23, - Placeholder(_) => 24, - Infer(_) => 25, - Error(_) => 26, + Pat(_, _) => 21, + Alias(_, _) => 22, + Param(_) => 23, + Bound(_, _) => 24, + Placeholder(_) => 25, + Infer(_) => 26, + Error(_) => 27, } } @@ -299,6 +307,7 @@ impl<I: Interner> PartialEq for TyKind<I> { (Adt(a_d, a_s), Adt(b_d, b_s)) => a_d == b_d && a_s == b_s, (Foreign(a_d), Foreign(b_d)) => a_d == b_d, (Array(a_t, a_c), Array(b_t, b_c)) => a_t == b_t && a_c == b_c, + (Pat(a_t, a_c), Pat(b_t, b_c)) => a_t == b_t && a_c == b_c, (Slice(a_t), Slice(b_t)) => a_t == b_t, (RawPtr(a_t, a_m), RawPtr(b_t, b_m)) => a_t == b_t && a_m == b_m, (Ref(a_r, a_t, a_m), Ref(b_r, b_t, b_m)) => a_r == b_r && a_t == b_t && a_m == b_m, @@ -322,7 +331,7 @@ impl<I: Interner> PartialEq for TyKind<I> { _ => { debug_assert!( tykind_discriminant(self) != tykind_discriminant(other), - "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}" + "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}" ); false } @@ -362,6 +371,7 @@ impl<I: Interner> DebugWithInfcx<I> for TyKind<I> { Foreign(d) => f.debug_tuple("Foreign").field(d).finish(), Str => write!(f, "str"), Array(t, c) => write!(f, "[{:?}; {:?}]", &this.wrap(t), &this.wrap(c)), + Pat(t, p) => write!(f, "pattern_type!({:?} is {:?})", &this.wrap(t), &this.wrap(p)), Slice(t) => write!(f, "[{:?}]", &this.wrap(t)), RawPtr(ty, mutbl) => { match mutbl { diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index d6a3f9f0749..2f588c67f56 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -110,6 +110,10 @@ pub trait TypeVisitor<I: Interner>: Sized { fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { p.super_visit_with(self) } + + fn visit_clauses(&mut self, p: I::Clauses) -> Self::Result { + p.super_visit_with(self) + } } /////////////////////////////////////////////////////////////////////////// @@ -423,6 +427,16 @@ impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor { ControlFlow::Continue(()) } } + + #[inline] + fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result { + // Note: no `super_visit_with` call. + if clauses.flags().intersects(self.flags) { + ControlFlow::Break(FoundFlags) + } else { + ControlFlow::Continue(()) + } + } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -515,6 +529,15 @@ impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor { ControlFlow::Continue(()) } } + + #[inline] + fn visit_clauses(&mut self, clauses: I::Clauses) -> Self::Result { + if clauses.outer_exclusive_binder() > self.outer_index { + ControlFlow::Break(FoundEscapingVars) + } else { + ControlFlow::Continue(()) + } + } } struct HasErrorVisitor; diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 8ed34fab54d..94c552199bc 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -8,7 +8,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; -use crate::mir::{Body, Place}; +use crate::mir::{BinOp, Body, Place}; use crate::target::MachineInfo; use crate::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -211,6 +211,9 @@ pub trait Context { /// Get a debug string representation of a place. fn place_pretty(&self, place: &Place) -> String; + + /// Get the resulting type of binary operation. + fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index 8f77a19fc0e..1ad05633d62 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1,3 +1,4 @@ +use crate::compiler_interface::with; use crate::mir::pretty::function_body; use crate::ty::{ AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability, Region, RigidTy, Ty, TyKind, @@ -337,42 +338,7 @@ impl BinOp { /// Return the type of this operation for the given input Ty. /// This function does not perform type checking, and it currently doesn't handle SIMD. pub fn ty(&self, lhs_ty: Ty, rhs_ty: Ty) -> Ty { - match self { - BinOp::Add - | BinOp::AddUnchecked - | BinOp::Sub - | BinOp::SubUnchecked - | BinOp::Mul - | BinOp::MulUnchecked - | BinOp::Div - | BinOp::Rem - | BinOp::BitXor - | BinOp::BitAnd - | BinOp::BitOr => { - assert_eq!(lhs_ty, rhs_ty); - assert!(lhs_ty.kind().is_primitive()); - lhs_ty - } - BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => { - assert!(lhs_ty.kind().is_primitive()); - assert!(rhs_ty.kind().is_primitive()); - lhs_ty - } - BinOp::Offset => { - assert!(lhs_ty.kind().is_raw_ptr()); - assert!(rhs_ty.kind().is_integral()); - lhs_ty - } - BinOp::Eq | BinOp::Lt | BinOp::Le | BinOp::Ne | BinOp::Ge | BinOp::Gt => { - assert_eq!(lhs_ty, rhs_ty); - let lhs_kind = lhs_ty.kind(); - assert!(lhs_kind.is_primitive() || lhs_kind.is_raw_ptr() || lhs_kind.is_fn_ptr()); - Ty::bool_ty() - } - BinOp::Cmp => { - unimplemented!("Should cmp::Ordering be a RigidTy?"); - } - } + with(|ctx| ctx.binop_ty(*self, lhs_ty, rhs_ty)) } } @@ -993,7 +959,7 @@ pub enum NullOp { AlignOf, /// Returns the offset of a field. OffsetOf(Vec<(VariantIdx, FieldIdx)>), - /// cfg!(debug_assertions), but at codegen time + /// cfg!(ub_checks), but at codegen time UbChecks, } diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs index 3e8d186b97e..bc6fb34493a 100644 --- a/compiler/stable_mir/src/ty.rs +++ b/compiler/stable_mir/src/ty.rs @@ -99,6 +99,12 @@ impl Ty { } } +/// Represents a pattern in the type system +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Pattern { + Range { start: Option<Const>, end: Option<Const>, include_end: bool }, +} + /// Represents a constant in MIR or from the Type system. #[derive(Clone, Debug, Eq, PartialEq)] pub struct Const { @@ -481,6 +487,7 @@ pub enum RigidTy { Foreign(ForeignDef), Str, Array(Ty, Const), + Pat(Ty, Pattern), Slice(Ty), RawPtr(Ty, Mutability), Ref(Region, Ty, Mutability), diff --git a/compiler/stable_mir/src/visitor.rs b/compiler/stable_mir/src/visitor.rs index 65e42879d61..2d7159f87fe 100644 --- a/compiler/stable_mir/src/visitor.rs +++ b/compiler/stable_mir/src/visitor.rs @@ -139,6 +139,7 @@ impl Visitable for RigidTy { t.visit(visitor)?; c.visit(visitor) } + RigidTy::Pat(t, _p) => t.visit(visitor), RigidTy::Slice(inner) => inner.visit(visitor), RigidTy::RawPtr(ty, _) => ty.visit(visitor), RigidTy::Ref(reg, ty, _) => { diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs index 638f343fb24..0561f49c967 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloc/benches/lib.rs @@ -1,6 +1,8 @@ // Disabling on android for the time being // See https://github.com/rust-lang/rust/issues/73535#event-3477699747 #![cfg(not(target_os = "android"))] +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] #![feature(btree_extract_if)] #![feature(iter_next_chunk)] #![feature(repr_simd)] diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 0421a12b3a9..8b145b67bf1 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -4,10 +4,14 @@ use crate::alloc::{self, Layout, LayoutError}; use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; +#[cfg(not(no_global_oom_handling))] +use core::intrinsics::const_allocate; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] use core::marker::Unsize; -use core::mem::{self, SizedTypeProperties}; +use core::mem; +#[cfg(not(no_global_oom_handling))] +use core::mem::SizedTypeProperties; use core::ops::{Deref, DerefMut}; use core::ptr::Pointee; use core::ptr::{self, NonNull}; @@ -109,9 +113,14 @@ impl<Dyn: ?Sized> ThinBox<Dyn> { where T: Unsize<Dyn>, { - let meta = ptr::metadata(&value as &Dyn); - let ptr = WithOpaqueHeader::new(meta, value); - ThinBox { ptr, _marker: PhantomData } + if mem::size_of::<T>() == 0 { + let ptr = WithOpaqueHeader::new_unsize_zst::<Dyn, T>(value); + ThinBox { ptr, _marker: PhantomData } + } else { + let meta = ptr::metadata(&value as &Dyn); + let ptr = WithOpaqueHeader::new(meta, value); + ThinBox { ptr, _marker: PhantomData } + } } } @@ -200,6 +209,16 @@ impl WithOpaqueHeader { Self(ptr.0) } + #[cfg(not(no_global_oom_handling))] + fn new_unsize_zst<Dyn, T>(value: T) -> Self + where + Dyn: ?Sized, + T: Unsize<Dyn>, + { + let ptr = WithHeader::<<Dyn as Pointee>::Metadata>::new_unsize_zst::<Dyn, T>(value); + Self(ptr.0) + } + fn try_new<H, T>(header: H, value: T) -> Result<Self, core::alloc::AllocError> { WithHeader::try_new(header, value).map(|ptr| Self(ptr.0)) } @@ -288,6 +307,58 @@ impl<H> WithHeader<H> { } } + // `Dyn` is `?Sized` type like `[u32]`, and `T` is ZST type like `[u32; 0]`. + #[cfg(not(no_global_oom_handling))] + fn new_unsize_zst<Dyn, T>(value: T) -> WithHeader<H> + where + Dyn: Pointee<Metadata = H> + ?Sized, + T: Unsize<Dyn>, + { + assert!(mem::size_of::<T>() == 0); + + const fn max(a: usize, b: usize) -> usize { + if a > b { a } else { b } + } + + // Compute a pointer to the right metadata. This will point to the beginning + // of the header, past the padding, so the assigned type makes sense. + // It also ensures that the address at the end of the header is sufficiently + // aligned for T. + let alloc: &<Dyn as Pointee>::Metadata = const { + // FIXME: just call `WithHeader::alloc_layout` with size reset to 0. + // Currently that's blocked on `Layout::extend` not being `const fn`. + + let alloc_align = + max(mem::align_of::<T>(), mem::align_of::<<Dyn as Pointee>::Metadata>()); + + let alloc_size = + max(mem::align_of::<T>(), mem::size_of::<<Dyn as Pointee>::Metadata>()); + + unsafe { + // SAFETY: align is power of two because it is the maximum of two alignments. + let alloc: *mut u8 = const_allocate(alloc_size, alloc_align); + + let metadata_offset = + alloc_size.checked_sub(mem::size_of::<<Dyn as Pointee>::Metadata>()).unwrap(); + // SAFETY: adding offset within the allocation. + let metadata_ptr: *mut <Dyn as Pointee>::Metadata = + alloc.add(metadata_offset).cast(); + // SAFETY: `*metadata_ptr` is within the allocation. + metadata_ptr.write(ptr::metadata::<Dyn>(ptr::dangling::<T>() as *const Dyn)); + + // SAFETY: we have just written the metadata. + &*(metadata_ptr) + } + }; + + // SAFETY: `alloc` points to `<Dyn as Pointee>::Metadata`, so addition stays in-bounds. + let value_ptr = + unsafe { (alloc as *const <Dyn as Pointee>::Metadata).add(1) }.cast::<T>().cast_mut(); + debug_assert!(value_ptr.is_aligned()); + mem::forget(value); + WithHeader(NonNull::new(value_ptr.cast()).unwrap(), PhantomData) + } + // Safety: // - Assumes that either `value` can be dereferenced, or is the // `NonNull::dangling()` we use when both `T` and `H` are ZSTs. @@ -300,20 +371,19 @@ impl<H> WithHeader<H> { impl<H> Drop for DropGuard<H> { fn drop(&mut self) { + // All ZST are allocated statically. + if self.value_layout.size() == 0 { + return; + } + unsafe { // SAFETY: Layout must have been computable if we're in drop let (layout, value_offset) = WithHeader::<H>::alloc_layout(self.value_layout).unwrap_unchecked(); - // Note: Don't deallocate if the layout size is zero, because the pointer - // didn't come from the allocator. - if layout.size() != 0 { - alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout); - } else { - debug_assert!( - value_offset == 0 && H::IS_ZST && self.value_layout.size() == 0 - ); - } + // Since we only allocate for non-ZSTs, the layout size cannot be zero. + debug_assert!(layout.size() != 0); + alloc::dealloc(self.ptr.as_ptr().sub(value_offset), layout); } } } diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index e2fc320f280..693ecb0b6b4 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -1614,7 +1614,10 @@ impl<T, A: Allocator> VecDeque<T, A> { let old_head = self.head; self.head = self.to_physical_idx(1); self.len -= 1; - Some(unsafe { self.buffer_read(old_head) }) + unsafe { + core::hint::assert_unchecked(self.len < self.capacity()); + Some(self.buffer_read(old_head)) + } } } @@ -1638,7 +1641,10 @@ impl<T, A: Allocator> VecDeque<T, A> { None } else { self.len -= 1; - Some(unsafe { self.buffer_read(self.to_physical_idx(self.len)) }) + unsafe { + core::hint::assert_unchecked(self.len < self.capacity()); + Some(self.buffer_read(self.to_physical_idx(self.len))) + } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cafd59cb0d9..f638c5cf8c7 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -56,11 +56,6 @@ //! [`Rc`]: rc //! [`RefCell`]: core::cell -// To run alloc tests without x.py without ending up with two copies of alloc, Miri needs to be -// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. -// rustc itself never sets the feature, so this line has no effect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] -// #![allow(unused_attributes)] #![stable(feature = "alloc", since = "1.36.0")] #![doc( @@ -71,7 +66,6 @@ #![doc(cfg_hide( not(test), not(any(test, bootstrap)), - any(not(feature = "miri-test-libstd"), test, doctest), no_global_oom_handling, not(no_global_oom_handling), not(no_rc), @@ -114,8 +108,10 @@ #![feature(const_box)] #![feature(const_cow_is_borrowed)] #![feature(const_eval_select)] +#![feature(const_heap)] #![feature(const_maybe_uninit_as_mut_ptr)] #![feature(const_maybe_uninit_write)] +#![feature(const_option)] #![feature(const_pin)] #![feature(const_refs_to_cell)] #![feature(const_size_of_val)] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4dea27221b7..6ae52cc7827 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1062,7 +1062,9 @@ impl<T, A: Allocator> Arc<T, A> { /// /// // Create a long list and clone it /// let mut x = LinkedList::new(); - /// for i in 0..100000 { + /// let size = 100000; + /// # let size = if cfg!(miri) { 100 } else { size }; + /// for i in 0..size { /// x.push(i); // Adds i to the front of x /// } /// let y = x.clone(); diff --git a/library/core/benches/lib.rs b/library/core/benches/lib.rs index 4d14b930e41..32d15c386cb 100644 --- a/library/core/benches/lib.rs +++ b/library/core/benches/lib.rs @@ -1,5 +1,7 @@ // wasm32 does not support benches (no time). #![cfg(not(target_arch = "wasm32"))] +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] #![feature(flt2dec)] #![feature(test)] #![feature(trusted_random_access)] diff --git a/library/core/src/async_iter/async_iter.rs b/library/core/src/async_iter/async_iter.rs index 489f95bbf10..a0ffb6d4750 100644 --- a/library/core/src/async_iter/async_iter.rs +++ b/library/core/src/async_iter/async_iter.rs @@ -116,6 +116,7 @@ where impl<T> Poll<Option<T>> { /// A helper function for internal desugaring -- produces `Ready(Some(t))`, /// which corresponds to the async iterator yielding a value. + #[doc(hidden)] #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenReady"] pub fn async_gen_ready(t: T) -> Self { @@ -124,6 +125,7 @@ impl<T> Poll<Option<T>> { /// A helper constant for internal desugaring -- produces `Pending`, /// which corresponds to the async iterator pending on an `.await`. + #[doc(hidden)] #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenPending"] // FIXME(gen_blocks): This probably could be deduplicated. @@ -131,6 +133,7 @@ impl<T> Poll<Option<T>> { /// A helper constant for internal desugaring -- produces `Ready(None)`, /// which corresponds to the async iterator finishing its iteration. + #[doc(hidden)] #[unstable(feature = "async_gen_internals", issue = "none")] #[lang = "AsyncGenFinished"] pub const FINISHED: Self = Poll::Ready(None); diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 0e719e169de..58b9ba4accb 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2071,6 +2071,7 @@ impl<T> UnsafeCell<T> { /// ``` #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] + // When this is const stabilized, please remove `primitive_into_inner` below. #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] pub const fn into_inner(self) -> T { self.value @@ -2217,6 +2218,47 @@ impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafeCell<U>> for UnsafeCell<T> {} #[unstable(feature = "dispatch_from_dyn", issue = "none")] impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafeCell<U>> for UnsafeCell<T> {} +// Special cases of UnsafeCell::into_inner where T is a primitive. These are +// used by Atomic*::into_inner. +// +// The real UnsafeCell::into_inner cannot be used yet in a stable const function. +// That is blocked on a "precise drop analysis" unstable const feature. +// https://github.com/rust-lang/rust/issues/73255 +macro_rules! unsafe_cell_primitive_into_inner { + ($($primitive:ident $atomic:literal)*) => { + $( + #[cfg(target_has_atomic_load_store = $atomic)] + impl UnsafeCell<$primitive> { + pub(crate) const fn primitive_into_inner(self) -> $primitive { + self.value + } + } + )* + }; +} + +unsafe_cell_primitive_into_inner! { + i8 "8" + u8 "8" + i16 "16" + u16 "16" + i32 "32" + u32 "32" + i64 "64" + u64 "64" + i128 "128" + u128 "128" + isize "ptr" + usize "ptr" +} + +#[cfg(target_has_atomic_load_store = "ptr")] +impl<T> UnsafeCell<*mut T> { + pub(crate) const fn primitive_into_inner(self) -> *mut T { + self.value + } +} + /// [`UnsafeCell`], but [`Sync`]. /// /// This is just an `UnsafeCell`, except it implements `Sync` diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 3877a0c48cb..a7c3dfc982d 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -164,6 +164,42 @@ impl<T> OnceCell<T> { } } + /// Gets the mutable reference of the contents of the cell, + /// initializing it with `f` if the cell was empty. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::cell::OnceCell; + /// + /// let mut cell = OnceCell::new(); + /// let value = cell.get_mut_or_init(|| 92); + /// assert_eq!(*value, 92); + /// + /// *value += 2; + /// assert_eq!(*value, 94); + /// + /// let value = cell.get_mut_or_init(|| unreachable!()); + /// assert_eq!(*value, 94); + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + match self.get_mut_or_try_init(|| Ok::<T, !>(f())) { + Ok(val) => val, + } + } + /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. @@ -200,16 +236,55 @@ impl<T> OnceCell<T> { if let Some(val) = self.get() { return Ok(val); } - /// Avoid inlining the initialization closure into the common path that fetches - /// the already initialized value - #[cold] - fn outlined_call<F, T, E>(f: F) -> Result<T, E> - where - F: FnOnce() -> Result<T, E>, - { - f() + self.try_init(f) + } + + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. If the cell was empty and `f` failed, + /// an error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::cell::OnceCell; + /// + /// let mut cell: OnceCell<u32> = OnceCell::new(); + /// + /// // Failed initializers do not change the value + /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); + /// assert!(cell.get().is_none()); + /// + /// let value = cell.get_mut_or_try_init(|| "1234".parse()); + /// assert_eq!(value, Ok(&mut 1234)); + /// *value.unwrap() += 2; + /// assert_eq!(cell.get(), Some(&1236)) + /// ``` + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result<T, E>, + { + if self.get().is_none() { + self.try_init(f)?; } - let val = outlined_call(f)?; + Ok(self.get_mut().unwrap()) + } + + // Avoid inlining the initialization closure into the common path that fetches + // the already initialized value + #[cold] + fn try_init<F, E>(&self, f: F) -> Result<&T, E> + where + F: FnOnce() -> Result<T, E>, + { + let val = f()?; // Note that *some* forms of reentrant initialization might lead to // UB (see `reentrant_init` test). I believe that just removing this // `panic`, while keeping `try_insert` would be sound, but it seems diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 6dd3069034d..f965afc8a59 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -81,7 +81,7 @@ pub trait Future { /// An implementation of `poll` should strive to return quickly, and should /// not block. Returning quickly prevents unnecessarily clogging up /// threads or event loops. If it is known ahead of time that a call to - /// `poll` may end up taking awhile, the work should be offloaded to a + /// `poll` may end up taking a while, the work should be offloaded to a /// thread pool (or something similar) to ensure that `poll` can return /// quickly. /// diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b09d9fab8a7..9406efd7ab2 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1128,7 +1128,7 @@ extern "rust-intrinsic" { /// any safety invariants. /// /// Consider using [`core::panic::Location::caller`] instead. - #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] + #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] #[rustc_safe_intrinsic] #[rustc_nounwind] pub fn caller_location() -> &'static crate::panic::Location<'static>; @@ -2704,17 +2704,17 @@ pub const unsafe fn typed_swap<T>(x: *mut T, y: *mut T) { } /// Returns whether we should perform some UB-checking at runtime. This eventually evaluates to -/// `cfg!(debug_assertions)`, but behaves different from `cfg!` when mixing crates built with different -/// flags: if the crate has debug assertions enabled or carries the `#[rustc_preserve_ub_checks]` +/// `cfg!(ub_checks)`, but behaves different from `cfg!` when mixing crates built with different +/// flags: if the crate has UB checks enabled or carries the `#[rustc_preserve_ub_checks]` /// attribute, evaluation is delayed until monomorphization (or until the call gets inlined into /// a crate that does not delay evaluation further); otherwise it can happen any time. /// -/// The common case here is a user program built with debug_assertions linked against the distributed -/// sysroot which is built without debug_assertions but with `#[rustc_preserve_ub_checks]`. +/// The common case here is a user program built with ub_checks linked against the distributed +/// sysroot which is built without ub_checks but with `#[rustc_preserve_ub_checks]`. /// For code that gets monomorphized in the user crate (i.e., generic functions and functions with -/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(debug_assertions)` means that -/// assertions are enabled whenever the *user crate* has debug assertions enabled. However if the -/// user has debug assertions disabled, the checks will still get optimized out. This intrinsic is +/// `#[inline]`), gating assertions on `ub_checks()` rather than `cfg!(ub_checks)` means that +/// assertions are enabled whenever the *user crate* has UB checks enabled. However if the +/// user has UB checks disabled, the checks will still get optimized out. This intrinsic is /// primarily used by [`ub_checks::assert_unsafe_precondition`]. #[rustc_const_unstable(feature = "const_ub_checks", issue = "none")] #[unstable(feature = "core_intrinsics", issue = "none")] diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index b8b96417d13..616dd0afc51 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -1,6 +1,7 @@ use crate::{ intrinsics, iter::{from_fn, TrustedLen, TrustedRandomAccess}, + num::NonZeroUsize, ops::{Range, Try}, }; @@ -22,7 +23,11 @@ pub struct StepBy<I> { /// Additionally this type-dependent preprocessing means specialized implementations /// cannot be used interchangeably. iter: I, - step: usize, + /// This field is `step - 1`, aka the correct amount to pass to `nth` when iterating. + /// It MUST NOT be `usize::MAX`, as `unsafe` code depends on being able to add one + /// without the risk of overflow. (This is important so that length calculations + /// don't need to check for division-by-zero, for example.) + step_minus_one: usize, first_take: bool, } @@ -31,7 +36,16 @@ impl<I> StepBy<I> { pub(in crate::iter) fn new(iter: I, step: usize) -> StepBy<I> { assert!(step != 0); let iter = <I as SpecRangeSetup<I>>::setup(iter, step); - StepBy { iter, step: step - 1, first_take: true } + StepBy { iter, step_minus_one: step - 1, first_take: true } + } + + /// The `step` that was originally passed to `Iterator::step_by(step)`, + /// aka `self.step_minus_one + 1`. + #[inline] + fn original_step(&self) -> NonZeroUsize { + // SAFETY: By type invariant, `step_minus_one` cannot be `MAX`, which + // means the addition cannot overflow and the result cannot be zero. + unsafe { NonZeroUsize::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) } } } @@ -81,8 +95,8 @@ where // The zero-based index starting from the end of the iterator of the // last element. Used in the `DoubleEndedIterator` implementation. fn next_back_index(&self) -> usize { - let rem = self.iter.len() % (self.step + 1); - if self.first_take { if rem == 0 { self.step } else { rem - 1 } } else { rem } + let rem = self.iter.len() % self.original_step(); + if self.first_take { if rem == 0 { self.step_minus_one } else { rem - 1 } } else { rem } } } @@ -209,7 +223,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { #[inline] default fn spec_next(&mut self) -> Option<I::Item> { - let step_size = if self.first_take { 0 } else { self.step }; + let step_size = if self.first_take { 0 } else { self.step_minus_one }; self.first_take = false; self.iter.nth(step_size) } @@ -217,22 +231,22 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { #[inline] default fn spec_size_hint(&self) -> (usize, Option<usize>) { #[inline] - fn first_size(step: usize) -> impl Fn(usize) -> usize { - move |n| if n == 0 { 0 } else { 1 + (n - 1) / (step + 1) } + fn first_size(step: NonZeroUsize) -> impl Fn(usize) -> usize { + move |n| if n == 0 { 0 } else { 1 + (n - 1) / step } } #[inline] - fn other_size(step: usize) -> impl Fn(usize) -> usize { - move |n| n / (step + 1) + fn other_size(step: NonZeroUsize) -> impl Fn(usize) -> usize { + move |n| n / step } let (low, high) = self.iter.size_hint(); if self.first_take { - let f = first_size(self.step); + let f = first_size(self.original_step()); (f(low), high.map(f)) } else { - let f = other_size(self.step); + let f = other_size(self.original_step()); (f(low), high.map(f)) } } @@ -247,10 +261,9 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { } n -= 1; } - // n and self.step are indices, we need to add 1 to get the amount of elements + // n and self.step_minus_one are indices, we need to add 1 to get the amount of elements // When calling `.nth`, we need to subtract 1 again to convert back to an index - // step + 1 can't overflow because `.step_by` sets `self.step` to `step - 1` - let mut step = self.step + 1; + let mut step = self.original_step().get(); // n + 1 could overflow // thus, if n is usize::MAX, instead of adding one, we call .nth(step) if n == usize::MAX { @@ -288,8 +301,11 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { R: Try<Output = Acc>, { #[inline] - fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth(step) + fn nth<I: Iterator>( + iter: &mut I, + step_minus_one: usize, + ) -> impl FnMut() -> Option<I::Item> + '_ { + move || iter.nth(step_minus_one) } if self.first_take { @@ -299,7 +315,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { Some(x) => acc = f(acc, x)?, } } - from_fn(nth(&mut self.iter, self.step)).try_fold(acc, f) + from_fn(nth(&mut self.iter, self.step_minus_one)).try_fold(acc, f) } default fn spec_fold<Acc, F>(mut self, mut acc: Acc, mut f: F) -> Acc @@ -307,8 +323,11 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { F: FnMut(Acc, Self::Item) -> Acc, { #[inline] - fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth(step) + fn nth<I: Iterator>( + iter: &mut I, + step_minus_one: usize, + ) -> impl FnMut() -> Option<I::Item> + '_ { + move || iter.nth(step_minus_one) } if self.first_take { @@ -318,7 +337,7 @@ unsafe impl<I: Iterator> StepByImpl<I> for StepBy<I> { Some(x) => acc = f(acc, x), } } - from_fn(nth(&mut self.iter, self.step)).fold(acc, f) + from_fn(nth(&mut self.iter, self.step_minus_one)).fold(acc, f) } } @@ -336,7 +355,7 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St // is out of bounds because the length of `self.iter` does not exceed // `usize::MAX` (because `I: ExactSizeIterator`) and `nth_back` is // zero-indexed - let n = n.saturating_mul(self.step + 1).saturating_add(self.next_back_index()); + let n = n.saturating_mul(self.original_step().get()).saturating_add(self.next_back_index()); self.iter.nth_back(n) } @@ -348,16 +367,16 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St #[inline] fn nth_back<I: DoubleEndedIterator>( iter: &mut I, - step: usize, + step_minus_one: usize, ) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth_back(step) + move || iter.nth_back(step_minus_one) } match self.next_back() { None => try { init }, Some(x) => { let acc = f(init, x)?; - from_fn(nth_back(&mut self.iter, self.step)).try_fold(acc, f) + from_fn(nth_back(&mut self.iter, self.step_minus_one)).try_fold(acc, f) } } } @@ -371,16 +390,16 @@ unsafe impl<I: DoubleEndedIterator + ExactSizeIterator> StepByBackImpl<I> for St #[inline] fn nth_back<I: DoubleEndedIterator>( iter: &mut I, - step: usize, + step_minus_one: usize, ) -> impl FnMut() -> Option<I::Item> + '_ { - move || iter.nth_back(step) + move || iter.nth_back(step_minus_one) } match self.next_back() { None => init, Some(x) => { let acc = f(init, x); - from_fn(nth_back(&mut self.iter, self.step)).fold(acc, f) + from_fn(nth_back(&mut self.iter, self.step_minus_one)).fold(acc, f) } } } @@ -424,8 +443,7 @@ macro_rules! spec_int_ranges { fn spec_next(&mut self) -> Option<$t> { // if a step size larger than the type has been specified fall back to // t::MAX, in which case remaining will be at most 1. - // The `+ 1` can't overflow since the constructor substracted 1 from the original value. - let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX); let remaining = self.iter.end; if remaining > 0 { let val = self.iter.start; @@ -474,7 +492,7 @@ macro_rules! spec_int_ranges { { // if a step size larger than the type has been specified fall back to // t::MAX, in which case remaining will be at most 1. - let step = <$t>::try_from(self.step + 1).unwrap_or(<$t>::MAX); + let step = <$t>::try_from(self.original_step().get()).unwrap_or(<$t>::MAX); let remaining = self.iter.end; let mut acc = init; let mut val = self.iter.start; @@ -500,7 +518,7 @@ macro_rules! spec_int_ranges_r { fn spec_next_back(&mut self) -> Option<Self::Item> where Range<$t>: DoubleEndedIterator + ExactSizeIterator, { - let step = (self.step + 1) as $t; + let step = self.original_step().get() as $t; let remaining = self.iter.end; if remaining > 0 { let start = self.iter.start; diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index d2c9e1554b4..95c03043e3e 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -1572,7 +1572,7 @@ pub trait Iterator { /// /// The returned iterator implements [`FusedIterator`], because once `self` /// returns `None`, even if it returns a `Some(T)` again in the next iterations, - /// we cannot put it into a contigious array buffer, and thus the returned iterator + /// we cannot put it into a contiguous array buffer, and thus the returned iterator /// should be fused. /// /// [`slice::windows()`]: slice::windows diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index ba19ca1f45d..0ba3a557a03 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -57,10 +57,7 @@ // // This cfg won't affect doc tests. #![cfg(not(test))] -// To run core tests without x.py without ending up with two copies of core, Miri needs to be -// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. -// rustc itself never sets the feature, so this line has no effect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] +// #![stable(feature = "core", since = "1.6.0")] #![doc( html_playground_url = "https://play.rust-lang.org/", @@ -71,7 +68,6 @@ #![doc(rust_logo)] #![doc(cfg_hide( not(test), - any(not(feature = "miri-test-libstd"), test, doctest), no_fp_fmt_parse, target_pointer_width = "16", target_pointer_width = "32", @@ -125,7 +121,6 @@ #![feature(const_array_into_iter_constructors)] #![feature(const_bigint_helper_methods)] #![feature(const_black_box)] -#![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_char_from_u32_unchecked)] #![feature(const_eval_select)] @@ -401,6 +396,9 @@ pub mod net; pub mod option; pub mod panic; pub mod panicking; +#[cfg(not(bootstrap))] +#[unstable(feature = "core_pattern_types", issue = "none")] +pub mod pat; pub mod pin; pub mod result; pub mod sync; diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 3f8c8efd416..483f55b2070 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -310,7 +310,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// This should be implemented consistently with the `branch` method such /// that applying the `?` operator will get back an equivalent residual: /// `FromResidual::from_residual(r).branch() --> ControlFlow::Break(r)`. - /// (It must not be an *identical* residual when interconversion is involved.) + /// (The residual is not mandated to be *identical* when interconversion is involved.) /// /// # Examples /// diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs index 6dcf23dde87..4ad507d8b86 100644 --- a/library/core/src/panic/location.rs +++ b/library/core/src/panic/location.rs @@ -81,7 +81,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] + #[rustc_const_stable(feature = "const_caller_location", since = "CURRENT_RUSTC_VERSION")] #[track_caller] #[inline] pub const fn caller() -> &'static Location<'static> { @@ -123,7 +123,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn file(&self) -> &str { self.file @@ -148,7 +148,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_hooks", since = "1.10.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn line(&self) -> u32 { self.line @@ -173,7 +173,7 @@ impl<'a> Location<'a> { /// ``` #[must_use] #[stable(feature = "panic_col", since = "1.25.0")] - #[rustc_const_unstable(feature = "const_location_fields", issue = "102911")] + #[rustc_const_stable(feature = "const_location_fields", since = "CURRENT_RUSTC_VERSION")] #[inline] pub const fn column(&self) -> u32 { self.col diff --git a/library/core/src/pat.rs b/library/core/src/pat.rs new file mode 100644 index 00000000000..a10c4593342 --- /dev/null +++ b/library/core/src/pat.rs @@ -0,0 +1,14 @@ +//! Helper module for exporting the `pattern_type` macro + +/// Creates a pattern type. +/// ```ignore (cannot test this from within core yet) +/// type Positive = std::pat::pattern_type!(i32 is 1..); +/// ``` +#[macro_export] +#[rustc_builtin_macro(pattern_type)] +#[unstable(feature = "core_pattern_type", issue = "none")] +macro_rules! pattern_type { + ($($arg:tt)*) => { + /* compiler built-in */ + }; +} diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 672af752149..ba2d6f64496 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -1,6 +1,7 @@ //! Trait implementations for `str`. use crate::cmp::Ordering; +use crate::intrinsics::unchecked_sub; use crate::ops; use crate::ptr; use crate::slice::SliceIndex; @@ -210,9 +211,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> { // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. - let ptr = unsafe { slice.as_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts(ptr, len) as *const str + unsafe { + let new_len = unchecked_sub(self.end, self.start); + ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) as *const str + } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { @@ -229,9 +231,10 @@ unsafe impl SliceIndex<str> for ops::Range<usize> { ); // SAFETY: see comments for `get_unchecked`. - let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts_mut(ptr, len) as *mut str + unsafe { + let new_len = unchecked_sub(self.end, self.start); + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) as *mut str + } } #[inline] fn index(self, slice: &str) -> &Self::Output { diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0a749fcb8f9..c8fd997a5da 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -578,9 +578,9 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] pub const fn into_inner(self) -> bool { - self.v.into_inner() != 0 + self.v.primitive_into_inner() != 0 } /// Loads a value from the bool. @@ -1397,9 +1397,9 @@ impl<T> AtomicPtr<T> { /// ``` #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] pub const fn into_inner(self) -> *mut T { - self.p.into_inner() + self.p.primitive_into_inner() } /// Loads a value from the pointer. @@ -2378,9 +2378,9 @@ macro_rules! atomic_int { /// ``` #[inline] #[$stable_access] - #[rustc_const_unstable(feature = "const_cell_into_inner", issue = "78729")] + #[rustc_const_stable(feature = "const_atomic_into_inner", since = "CURRENT_RUSTC_VERSION")] pub const fn into_inner(self) -> $int_type { - self.v.into_inner() + self.v.primitive_into_inner() } /// Loads a value from the atomic integer. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 8c5e5ecf5fe..0c87860096f 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -11,7 +11,6 @@ #![feature(const_align_offset)] #![feature(const_align_of_val_raw)] #![feature(const_black_box)] -#![feature(const_caller_location)] #![feature(const_cell_into_inner)] #![feature(const_hash)] #![feature(const_heap)] @@ -25,7 +24,6 @@ #![cfg_attr(not(bootstrap), feature(const_three_way_compare))] #![feature(const_trait_impl)] #![feature(const_likely)] -#![feature(const_location_fields)] #![feature(core_intrinsics)] #![feature(core_io_borrowed_buf)] #![feature(core_private_bignum)] diff --git a/library/std/benches/lib.rs b/library/std/benches/lib.rs index 4d1cf7fab7b..1b21c230a0b 100644 --- a/library/std/benches/lib.rs +++ b/library/std/benches/lib.rs @@ -1,3 +1,5 @@ +// Disabling in Miri as these would take too long. +#![cfg(not(miri))] #![feature(test)] extern crate test; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 31a8711e0eb..c713eefc72c 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -212,13 +212,7 @@ //! [rust-discord]: https://discord.gg/rust-lang //! [array]: prim@array //! [slice]: prim@slice -// To run std tests without x.py without ending up with two copies of std, Miri needs to be -// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>. -// rustc itself never sets the feature, so this line has no effect there. -#![cfg(any(not(feature = "miri-test-libstd"), test, doctest))] -// miri-test-libstd also prefers to make std use the sysroot versions of the dependencies. -#![cfg_attr(feature = "miri-test-libstd", feature(rustc_private))] -// + #![cfg_attr(not(feature = "restricted-std"), stable(feature = "rust1", since = "1.0.0"))] #![cfg_attr(feature = "restricted-std", unstable(feature = "restricted_std", issue = "none"))] #![cfg_attr(not(bootstrap), rustc_preserve_ub_checks)] @@ -582,6 +576,9 @@ pub mod net; pub mod num; pub mod os; pub mod panic; +#[cfg(not(bootstrap))] +#[unstable(feature = "core_pattern_types", issue = "none")] +pub mod pat; pub mod path; pub mod process; pub mod sync; diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs index 1be3acf5d43..15ab2250122 100644 --- a/library/std/src/os/windows/process.rs +++ b/library/std/src/os/windows/process.rs @@ -199,8 +199,60 @@ pub trait CommandExt: Sealed { /// Append literal text to the command line without any quoting or escaping. /// - /// This is useful for passing arguments to `cmd.exe /c`, which doesn't follow - /// `CommandLineToArgvW` escaping rules. + /// This is useful for passing arguments to applications which doesn't follow + /// the standard C run-time escaping rules, such as `cmd.exe /c`. + /// + /// # Bat files + /// + /// Note the `cmd /c` command line has slightly different escaping rules then bat files + /// themselves. If possible, it may be better to write complex arguments to a temporary + /// .bat file, with appropriate escaping, and simply run that using: + /// + /// ```no_run + /// # use std::process::Command; + /// # let temp_bat_file = ""; + /// # #[allow(unused)] + /// let output = Command::new("cmd").args(["/c", &format!("\"{temp_bat_file}\"")]).output(); + /// ``` + /// + /// # Example + /// + /// Run a bat script using both trusted and untrusted arguments. + /// + /// ```no_run + /// #[cfg(windows)] + /// // `my_script_path` is a path to known bat file. + /// // `user_name` is an untrusted name given by the user. + /// fn run_script( + /// my_script_path: &str, + /// user_name: &str, + /// ) -> Result<std::process::Output, std::io::Error> { + /// use std::io::{Error, ErrorKind}; + /// use std::os::windows::process::CommandExt; + /// use std::process::Command; + /// + /// // Create the command line, making sure to quote the script path. + /// // This assumes the fixed arguments have been tested to work with the script we're using. + /// let mut cmd_args = format!(r#""{my_script_path}" "--features=[a,b,c]""#); + /// + /// // Make sure the user name is safe. In particular we need to be + /// // cautious of ascii symbols that cmd may interpret specially. + /// // Here we only allow alphanumeric characters. + /// if !user_name.chars().all(|c| c.is_alphanumeric()) { + /// return Err(Error::new(ErrorKind::InvalidInput, "invalid user name")); + /// } + /// // now we've checked the user name, let's add that too. + /// cmd_args.push(' '); + /// cmd_args.push_str(&format!("--user {user_name}")); + /// + /// // call cmd.exe and return the output + /// Command::new("cmd.exe") + /// .arg("/c") + /// // surround the entire command in an extra pair of quotes, as required by cmd.exe. + /// .raw_arg(&format!("\"{cmd_args}\"")) + /// .output() + /// } + /// ```` #[stable(feature = "windows_process_extensions_raw_arg", since = "1.62.0")] fn raw_arg<S: AsRef<OsStr>>(&mut self, text_to_append_as_is: S) -> &mut process::Command; diff --git a/library/std/src/pat.rs b/library/std/src/pat.rs new file mode 100644 index 00000000000..aeddd84c2cb --- /dev/null +++ b/library/std/src/pat.rs @@ -0,0 +1,3 @@ +//! Helper module for exporting the `pattern_type` macro + +pub use core::pattern_type; diff --git a/library/std/src/process.rs b/library/std/src/process.rs index b84d5f11954..69cc61b30ef 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -88,6 +88,47 @@ //! assert_eq!(b"test", output.stdout.as_slice()); //! ``` //! +//! # Windows argument splitting +//! +//! On Unix systems arguments are passed to a new process as an array of strings +//! but on Windows arguments are passed as a single commandline string and it's +//! up to the child process to parse it into an array. Therefore the parent and +//! child processes must agree on how the commandline string is encoded. +//! +//! Most programs use the standard C run-time `argv`, which in practice results +//! in consistent argument handling. However some programs have their own way of +//! parsing the commandline string. In these cases using [`arg`] or [`args`] may +//! result in the child process seeing a different array of arguments then the +//! parent process intended. +//! +//! Two ways of mitigating this are: +//! +//! * Validate untrusted input so that only a safe subset is allowed. +//! * Use [`raw_arg`] to build a custom commandline. This bypasses the escaping +//! rules used by [`arg`] so should be used with due caution. +//! +//! `cmd.exe` and `.bat` use non-standard argument parsing and are especially +//! vulnerable to malicious input as they may be used to run arbitrary shell +//! commands. Untrusted arguments should be restricted as much as possible. +//! For examples on handling this see [`raw_arg`]. +//! +//! ### Bat file special handling +//! +//! On Windows, `Command` uses the Windows API function [`CreateProcessW`] to +//! spawn new processes. An undocumented feature of this function is that, +//! when given a `.bat` file as the application to run, it will automatically +//! convert that into running `cmd.exe /c` with the bat file as the next argument. +//! +//! For historical reasons Rust currently preserves this behaviour when using +//! [`Command::new`], and escapes the arguments according to `cmd.exe` rules. +//! Due to the complexity of `cmd.exe` argument handling, it might not be +//! possible to safely escape some special chars, and using them will result +//! in an error being returned at process spawn. The set of unescapeable +//! special chars might change between releases. +//! +//! Also note that running `.bat` scripts in this way may be removed in the +//! future and so should not be relied upon. +//! //! [`spawn`]: Command::spawn //! [`output`]: Command::output //! @@ -97,6 +138,12 @@ //! //! [`Write`]: io::Write //! [`Read`]: io::Read +//! +//! [`arg`]: Command::arg +//! [`args`]: Command::args +//! [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg +//! +//! [`CreateProcessW`]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw #![stable(feature = "process", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] @@ -611,6 +658,22 @@ impl Command { /// escaped characters, word splitting, glob patterns, variable substitution, etc. /// have no effect. /// + /// <div class="warning"> + /// + /// On Windows use caution with untrusted inputs. Most applications use the + /// standard convention for decoding arguments passed to them. These are safe to use with `arg`. + /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments + /// and are therefore vulnerable to malicious input. + /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands. + /// + /// See [Windows argument splitting][windows-args] for more details + /// or [`raw_arg`] for manually implementing non-standard argument encoding. + /// + /// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg + /// [windows-args]: crate::process#windows-argument-splitting + /// + /// </div> + /// /// # Examples /// /// Basic usage: @@ -641,6 +704,22 @@ impl Command { /// escaped characters, word splitting, glob patterns, variable substitution, etc. /// have no effect. /// + /// <div class="warning"> + /// + /// On Windows use caution with untrusted inputs. Most applications use the + /// standard convention for decoding arguments passed to them. These are safe to use with `args`. + /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments + /// and are therefore vulnerable to malicious input. + /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands. + /// + /// See [Windows argument splitting][windows-args] for more details + /// or [`raw_arg`] for manually implementing non-standard argument encoding. + /// + /// [`raw_arg`]: crate::os::windows::process::CommandExt::raw_arg + /// [windows-args]: crate::process#windows-argument-splitting + /// + /// </div> + /// /// # Examples /// /// Basic usage: diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 6d068613f8f..fc830bacced 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -252,6 +252,46 @@ impl<T> OnceLock<T> { } } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. + /// + /// Many threads may call `get_mut_or_init` concurrently with different + /// initializing functions, but it is guaranteed that only one function + /// will be executed. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and the cell + /// remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell = OnceLock::new(); + /// let value = cell.get_mut_or_init(|| 92); + /// assert_eq!(*value, 92); + /// + /// *value += 2; + /// assert_eq!(*value, 94); + /// + /// let value = cell.get_mut_or_init(|| unreachable!()); + /// assert_eq!(*value, 94); + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_init<F>(&mut self, f: F) -> &mut T + where + F: FnOnce() -> T, + { + match self.get_mut_or_try_init(|| Ok::<T, !>(f())) { + Ok(val) => val, + } + } + /// Gets the contents of the cell, initializing it with `f` if /// the cell was empty. If the cell was empty and `f` failed, an /// error is returned. @@ -303,6 +343,47 @@ impl<T> OnceLock<T> { Ok(unsafe { self.get_unchecked() }) } + /// Gets the mutable reference of the contents of the cell, initializing + /// it with `f` if the cell was empty. If the cell was empty and `f` failed, + /// an error is returned. + /// + /// # Panics + /// + /// If `f` panics, the panic is propagated to the caller, and + /// the cell remains uninitialized. + /// + /// # Examples + /// + /// ``` + /// #![feature(once_cell_get_mut)] + /// + /// use std::sync::OnceLock; + /// + /// let mut cell: OnceLock<u32> = OnceLock::new(); + /// + /// // Failed initializers do not change the value + /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); + /// assert!(cell.get().is_none()); + /// + /// let value = cell.get_mut_or_try_init(|| "1234".parse()); + /// assert_eq!(value, Ok(&mut 1234)); + /// *value.unwrap() += 2; + /// assert_eq!(cell.get(), Some(&1236)) + /// ``` + #[inline] + #[unstable(feature = "once_cell_get_mut", issue = "121641")] + pub fn get_mut_or_try_init<F, E>(&mut self, f: F) -> Result<&mut T, E> + where + F: FnOnce() -> Result<T, E>, + { + if self.get().is_none() { + self.initialize(f)?; + } + debug_assert!(self.is_initialized()); + // SAFETY: The inner value has been initialized + Ok(unsafe { self.get_unchecked_mut() }) + } + /// Consumes the `OnceLock`, returning the wrapped value. Returns /// `None` if the cell was empty. /// diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs index 5eb828fea1f..962577bb1ed 100644 --- a/library/std/src/sys/pal/hermit/fd.rs +++ b/library/std/src/sys/pal/hermit/fd.rs @@ -48,6 +48,11 @@ impl FileDesc { pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { unsupported() } + + pub fn fstat(&self, stat: *mut abi::stat) -> io::Result<()> { + cvt(unsafe { abi::fstat(self.fd.as_raw_fd(), stat) })?; + Ok(()) + } } impl<'a> Read for &'a FileDesc { diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs index d4da53fd3df..6519cc22f1f 100644 --- a/library/std/src/sys/pal/hermit/fs.rs +++ b/library/std/src/sys/pal/hermit/fs.rs @@ -1,12 +1,17 @@ -use super::abi::{self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY}; +use super::abi::{ + self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT, + O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, +}; use super::fd::FileDesc; -use crate::ffi::{CStr, OsString}; +use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; -use crate::hash::{Hash, Hasher}; use crate::io::{self, Error, ErrorKind}; use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom}; +use crate::mem; +use crate::os::hermit::ffi::OsStringExt; use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; use crate::path::{Path, PathBuf}; +use crate::sync::Arc; use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::cvt; use crate::sys::time::SystemTime; @@ -14,16 +19,53 @@ use crate::sys::unsupported; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; pub use crate::sys_common::fs::{copy, try_exists}; -//pub use crate::sys_common::fs::remove_dir_all; #[derive(Debug)] pub struct File(FileDesc); +#[derive(Clone)] +pub struct FileAttr { + stat_val: stat_struct, +} -pub struct FileAttr(!); +impl FileAttr { + fn from_stat(stat_val: stat_struct) -> Self { + Self { stat_val } + } +} -pub struct ReadDir(!); +// all DirEntry's will have a reference to this struct +struct InnerReadDir { + root: PathBuf, + dir: Vec<u8>, +} -pub struct DirEntry(!); +impl InnerReadDir { + pub fn new(root: PathBuf, dir: Vec<u8>) -> Self { + Self { root, dir } + } +} + +pub struct ReadDir { + inner: Arc<InnerReadDir>, + pos: i64, +} + +impl ReadDir { + fn new(inner: InnerReadDir) -> Self { + Self { inner: Arc::new(inner), pos: 0 } + } +} + +pub struct DirEntry { + /// path to the entry + root: PathBuf, + /// 64-bit inode number + ino: u64, + /// File type + type_: u32, + /// name of the entry + name: OsString, +} #[derive(Clone, Debug)] pub struct OpenOptions { @@ -41,72 +83,87 @@ pub struct OpenOptions { #[derive(Copy, Clone, Debug, Default)] pub struct FileTimes {} -pub struct FilePermissions(!); - -pub struct FileType(!); +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct FilePermissions { + mode: u32, +} -#[derive(Debug)] -pub struct DirBuilder {} +#[derive(Copy, Clone, Eq, Debug)] +pub struct FileType { + mode: u32, +} -impl FileAttr { - pub fn size(&self) -> u64 { - self.0 +impl PartialEq for FileType { + fn eq(&self, other: &Self) -> bool { + self.mode == other.mode } +} - pub fn perm(&self) -> FilePermissions { - self.0 +impl core::hash::Hash for FileType { + fn hash<H: core::hash::Hasher>(&self, state: &mut H) { + self.mode.hash(state); } +} - pub fn file_type(&self) -> FileType { - self.0 - } +#[derive(Debug)] +pub struct DirBuilder { + mode: u32, +} +impl FileAttr { pub fn modified(&self) -> io::Result<SystemTime> { - self.0 + Ok(SystemTime::new( + self.stat_val.st_mtime.try_into().unwrap(), + self.stat_val.st_mtime_nsec.try_into().unwrap(), + )) } pub fn accessed(&self) -> io::Result<SystemTime> { - self.0 + Ok(SystemTime::new( + self.stat_val.st_atime.try_into().unwrap(), + self.stat_val.st_atime_nsec.try_into().unwrap(), + )) } pub fn created(&self) -> io::Result<SystemTime> { - self.0 + Ok(SystemTime::new( + self.stat_val.st_ctime.try_into().unwrap(), + self.stat_val.st_ctime_nsec.try_into().unwrap(), + )) } -} -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - self.0 + pub fn size(&self) -> u64 { + self.stat_val.st_size as u64 } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - self.0 + pub fn perm(&self) -> FilePermissions { + FilePermissions { mode: (self.stat_val.st_mode) } } - pub fn set_readonly(&mut self, _readonly: bool) { - self.0 + pub fn file_type(&self) -> FileType { + let masked_mode = self.stat_val.st_mode & S_IFMT; + let mode = match masked_mode { + S_IFDIR => DT_DIR, + S_IFLNK => DT_LNK, + S_IFREG => DT_REG, + _ => DT_UNKNOWN, + }; + FileType { mode: mode } } } -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - self.0 +impl FilePermissions { + pub fn readonly(&self) -> bool { + // check if any class (owner, group, others) has write permission + self.mode & 0o222 == 0 } -} -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - self.0 + pub fn set_readonly(&mut self, _readonly: bool) { + unimplemented!() } -} - -impl Eq for FilePermissions {} -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + #[allow(dead_code)] + pub fn mode(&self) -> u32 { + self.mode as u32 } } @@ -117,49 +174,21 @@ impl FileTimes { impl FileType { pub fn is_dir(&self) -> bool { - self.0 + self.mode == DT_DIR } - pub fn is_file(&self) -> bool { - self.0 + self.mode == DT_REG } - pub fn is_symlink(&self) -> bool { - self.0 - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - self.0 - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - self.0 - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash<H: Hasher>(&self, _h: &mut H) { - self.0 - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + self.mode == DT_LNK } } impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e.g. 'ReadDir("/home")' + fmt::Debug::fmt(&*self.inner.root, f) } } @@ -167,25 +196,78 @@ impl Iterator for ReadDir { type Item = io::Result<DirEntry>; fn next(&mut self) -> Option<io::Result<DirEntry>> { - self.0 + let mut counter: usize = 0; + let mut offset: i64 = 0; + + // loop over all directory entries and search the entry for the current position + loop { + // leave function, if the loop reaches the of the buffer (with all entries) + if offset >= self.inner.dir.len().try_into().unwrap() { + return None; + } + + let dir = unsafe { + &*(self.inner.dir.as_ptr().offset(offset.try_into().unwrap()) as *const dirent64) + }; + + if counter == self.pos.try_into().unwrap() { + self.pos += 1; + + // After dirent64, the file name is stored. d_reclen represents the length of the dirent64 + // plus the length of the file name. Consequently, file name has a size of d_reclen minus + // the size of dirent64. The file name is always a C string and terminated by `\0`. + // Consequently, we are able to ignore the last byte. + let name_bytes = unsafe { + core::slice::from_raw_parts( + &dir.d_name as *const _ as *const u8, + dir.d_reclen as usize - core::mem::size_of::<dirent64>() - 1, + ) + .to_vec() + }; + let entry = DirEntry { + root: self.inner.root.clone(), + ino: dir.d_ino, + type_: dir.d_type as u32, + name: OsString::from_vec(name_bytes), + }; + + return Some(Ok(entry)); + } + + counter += 1; + + // move to the next dirent64, which is directly stored after the previous one + offset = offset + dir.d_off; + } } } impl DirEntry { pub fn path(&self) -> PathBuf { - self.0 + self.root.join(self.file_name_os_str()) } pub fn file_name(&self) -> OsString { - self.0 + self.file_name_os_str().to_os_string() } pub fn metadata(&self) -> io::Result<FileAttr> { - self.0 + let mut path = self.path(); + path.set_file_name(self.file_name_os_str()); + lstat(&path) } pub fn file_type(&self) -> io::Result<FileType> { - self.0 + Ok(FileType { mode: self.type_ as u32 }) + } + + #[allow(dead_code)] + pub fn ino(&self) -> u64 { + self.ino + } + + pub fn file_name_os_str(&self) -> &OsStr { + self.name.as_os_str() } } @@ -288,7 +370,9 @@ impl File { } pub fn file_attr(&self) -> io::Result<FileAttr> { - Err(Error::from_raw_os_error(22)) + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + self.0.fstat(&mut stat_val)?; + Ok(FileAttr::from_stat(stat_val)) } pub fn fsync(&self) -> io::Result<()> { @@ -357,11 +441,18 @@ impl File { impl DirBuilder { pub fn new() -> DirBuilder { - DirBuilder {} + DirBuilder { mode: 0o777 } } - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() + pub fn mkdir(&self, path: &Path) -> io::Result<()> { + run_path_with_cstr(path, &|path| { + cvt(unsafe { abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ()) + }) + } + + #[allow(dead_code)] + pub fn set_mode(&mut self, mode: u32) { + self.mode = mode as u32; } } @@ -416,8 +507,43 @@ impl FromRawFd for File { } } -pub fn readdir(_p: &Path) -> io::Result<ReadDir> { - unsupported() +pub fn readdir(path: &Path) -> io::Result<ReadDir> { + let fd_raw = run_path_with_cstr(path, &|path| cvt(unsafe { abi::opendir(path.as_ptr()) }))?; + let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) }; + let root = path.to_path_buf(); + + // read all director entries + let mut vec: Vec<u8> = Vec::new(); + let mut sz = 512; + loop { + // reserve memory to receive all directory entries + vec.resize(sz, 0); + + let readlen = + unsafe { abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) }; + if readlen > 0 { + // shrink down to the minimal size + vec.resize(readlen.try_into().unwrap(), 0); + break; + } + + // if the buffer is too small, getdents64 returns EINVAL + // otherwise, getdents64 returns an error number + if readlen != (-abi::errno::EINVAL).into() { + return Err(Error::from_raw_os_error(readlen.try_into().unwrap())); + } + + // we don't have enough memory => try to increase the vector size + sz = sz * 2; + + // 1 MB for directory entries should be enough + // stop here to avoid an endless loop + if sz > 0x100000 { + return Err(Error::from(ErrorKind::Uncategorized)); + } + } + + Ok(ReadDir::new(InnerReadDir::new(root, vec))) } pub fn unlink(path: &Path) -> io::Result<()> { @@ -428,17 +554,16 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { unsupported() } -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} +pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + Err(Error::from_raw_os_error(22)) } -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() +pub fn rmdir(path: &Path) -> io::Result<()> { + run_path_with_cstr(path, &|path| cvt(unsafe { abi::rmdir(path.as_ptr()) }).map(|_| ())) } pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - //unsupported() - Ok(()) + unsupported() } pub fn readlink(_p: &Path) -> io::Result<PathBuf> { @@ -453,12 +578,20 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { unsupported() } -pub fn stat(_p: &Path) -> io::Result<FileAttr> { - unsupported() +pub fn stat(path: &Path) -> io::Result<FileAttr> { + run_path_with_cstr(path, &|path| { + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + cvt(unsafe { abi::stat(path.as_ptr(), &mut stat_val) })?; + Ok(FileAttr::from_stat(stat_val)) + }) } -pub fn lstat(_p: &Path) -> io::Result<FileAttr> { - unsupported() +pub fn lstat(path: &Path) -> io::Result<FileAttr> { + run_path_with_cstr(path, &|path| { + let mut stat_val: stat_struct = unsafe { mem::zeroed() }; + cvt(unsafe { abi::lstat(path.as_ptr(), &mut stat_val) })?; + Ok(FileAttr::from_stat(stat_val)) + }) } pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> { diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 319b835a768..d6f9e4c1476 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -18,6 +18,12 @@ impl Timespec { Timespec { t: timespec { tv_sec: 0, tv_nsec: 0 } } } + const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec { + assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64); + // SAFETY: The assert above checks tv_nsec is within the valid range + Timespec { t: timespec { tv_sec: tv_sec, tv_nsec: tv_nsec } } + } + fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { if self >= other { Ok(if self.t.tv_nsec >= other.t.tv_nsec { @@ -195,6 +201,10 @@ pub struct SystemTime(Timespec); pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { + pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime { + SystemTime(Timespec::new(tv_sec, tv_nsec)) + } + pub fn now() -> SystemTime { let mut time: Timespec = Timespec::zero(); let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) }; diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index 96f64051cda..e8430b6ae70 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -1,10 +1,13 @@ // miri has some special hacks here that make things unused. #![cfg_attr(miri, allow(unused))] +#[cfg(test)] +mod tests; + use crate::os::unix::prelude::*; use crate::ffi::{CStr, OsStr, OsString}; -use crate::fmt; +use crate::fmt::{self, Write as _}; use crate::io::{self, BorrowedCursor, Error, IoSlice, IoSliceMut, SeekFrom}; use crate::mem; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd}; @@ -356,7 +359,7 @@ pub struct DirEntry { entry: dirent64, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct OpenOptions { // generic read: bool, @@ -370,7 +373,7 @@ pub struct OpenOptions { mode: mode_t, } -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq)] pub struct FilePermissions { mode: mode_t, } @@ -389,7 +392,7 @@ pub struct FileTimes { created: Option<SystemTime>, } -#[derive(Copy, Clone, Eq, Debug)] +#[derive(Copy, Clone, Eq)] pub struct FileType { mode: mode_t, } @@ -406,11 +409,13 @@ impl core::hash::Hash for FileType { } } -#[derive(Debug)] pub struct DirBuilder { mode: mode_t, } +#[derive(Copy, Clone)] +struct Mode(mode_t); + cfg_has_statx! {{ impl FileAttr { fn from_stat64(stat: stat64) -> Self { @@ -689,12 +694,26 @@ impl FileType { } } +impl fmt::Debug for FileType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let FileType { mode } = self; + f.debug_struct("FileType").field("mode", &Mode(*mode)).finish() + } +} + impl FromInner<u32> for FilePermissions { fn from_inner(mode: u32) -> FilePermissions { FilePermissions { mode: mode as mode_t } } } +impl fmt::Debug for FilePermissions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let FilePermissions { mode } = self; + f.debug_struct("FilePermissions").field("mode", &Mode(*mode)).finish() + } +} + impl fmt::Debug for ReadDir { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. @@ -1135,6 +1154,23 @@ impl OpenOptions { } } +impl fmt::Debug for OpenOptions { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let OpenOptions { read, write, append, truncate, create, create_new, custom_flags, mode } = + self; + f.debug_struct("OpenOptions") + .field("read", read) + .field("write", write) + .field("append", append) + .field("truncate", truncate) + .field("create", create) + .field("create_new", create_new) + .field("custom_flags", custom_flags) + .field("mode", &Mode(*mode)) + .finish() + } +} + impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { run_path_with_cstr(path, &|path| File::open_c(path, opts)) @@ -1425,6 +1461,13 @@ impl DirBuilder { } } +impl fmt::Debug for DirBuilder { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let DirBuilder { mode } = self; + f.debug_struct("DirBuilder").field("mode", &Mode(*mode)).finish() + } +} + impl AsInner<FileDesc> for File { #[inline] fn as_inner(&self) -> &FileDesc { @@ -1597,6 +1640,73 @@ impl fmt::Debug for File { } } +// Format in octal, followed by the mode format used in `ls -l`. +// +// References: +// https://pubs.opengroup.org/onlinepubs/009696899/utilities/ls.html +// https://www.gnu.org/software/libc/manual/html_node/Testing-File-Type.html +// https://www.gnu.org/software/libc/manual/html_node/Permission-Bits.html +// +// Example: +// 0o100664 (-rw-rw-r--) +impl fmt::Debug for Mode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Self(mode) = *self; + write!(f, "0o{mode:06o}")?; + + let entry_type = match mode & libc::S_IFMT { + libc::S_IFDIR => 'd', + libc::S_IFBLK => 'b', + libc::S_IFCHR => 'c', + libc::S_IFLNK => 'l', + libc::S_IFIFO => 'p', + libc::S_IFREG => '-', + _ => return Ok(()), + }; + + f.write_str(" (")?; + f.write_char(entry_type)?; + + // Owner permissions + f.write_char(if mode & libc::S_IRUSR != 0 { 'r' } else { '-' })?; + f.write_char(if mode & libc::S_IWUSR != 0 { 'w' } else { '-' })?; + let owner_executable = mode & libc::S_IXUSR != 0; + let setuid = mode as c_int & libc::S_ISUID as c_int != 0; + f.write_char(match (owner_executable, setuid) { + (true, true) => 's', // executable and setuid + (false, true) => 'S', // setuid + (true, false) => 'x', // executable + (false, false) => '-', + })?; + + // Group permissions + f.write_char(if mode & libc::S_IRGRP != 0 { 'r' } else { '-' })?; + f.write_char(if mode & libc::S_IWGRP != 0 { 'w' } else { '-' })?; + let group_executable = mode & libc::S_IXGRP != 0; + let setgid = mode as c_int & libc::S_ISGID as c_int != 0; + f.write_char(match (group_executable, setgid) { + (true, true) => 's', // executable and setgid + (false, true) => 'S', // setgid + (true, false) => 'x', // executable + (false, false) => '-', + })?; + + // Other permissions + f.write_char(if mode & libc::S_IROTH != 0 { 'r' } else { '-' })?; + f.write_char(if mode & libc::S_IWOTH != 0 { 'w' } else { '-' })?; + let other_executable = mode & libc::S_IXOTH != 0; + let sticky = mode as c_int & libc::S_ISVTX as c_int != 0; + f.write_char(match (entry_type, other_executable, sticky) { + ('d', true, true) => 't', // searchable and restricted deletion + ('d', false, true) => 'T', // restricted deletion + (_, true, _) => 'x', // executable + (_, false, _) => '-', + })?; + + f.write_char(')') + } +} + pub fn readdir(path: &Path) -> io::Result<ReadDir> { let ptr = run_path_with_cstr(path, &|p| unsafe { Ok(libc::opendir(p.as_ptr())) })?; if ptr.is_null() { @@ -1847,39 +1957,9 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { use crate::sync::atomic::{AtomicBool, Ordering}; - const COPYFILE_ACL: u32 = 1 << 0; - const COPYFILE_STAT: u32 = 1 << 1; - const COPYFILE_XATTR: u32 = 1 << 2; - const COPYFILE_DATA: u32 = 1 << 3; - - const COPYFILE_SECURITY: u32 = COPYFILE_STAT | COPYFILE_ACL; - const COPYFILE_METADATA: u32 = COPYFILE_SECURITY | COPYFILE_XATTR; - const COPYFILE_ALL: u32 = COPYFILE_METADATA | COPYFILE_DATA; - - const COPYFILE_STATE_COPIED: u32 = 8; - - #[allow(non_camel_case_types)] - type copyfile_state_t = *mut libc::c_void; - #[allow(non_camel_case_types)] - type copyfile_flags_t = u32; - - extern "C" { - fn fcopyfile( - from: libc::c_int, - to: libc::c_int, - state: copyfile_state_t, - flags: copyfile_flags_t, - ) -> libc::c_int; - fn copyfile_state_alloc() -> copyfile_state_t; - fn copyfile_state_free(state: copyfile_state_t) -> libc::c_int; - fn copyfile_state_get( - state: copyfile_state_t, - flag: u32, - dst: *mut libc::c_void, - ) -> libc::c_int; - } - - struct FreeOnDrop(copyfile_state_t); + const COPYFILE_ALL: libc::copyfile_flags_t = libc::COPYFILE_METADATA | libc::COPYFILE_DATA; + + struct FreeOnDrop(libc::copyfile_state_t); impl Drop for FreeOnDrop { fn drop(&mut self) { // The code below ensures that `FreeOnDrop` is never a null pointer @@ -1887,7 +1967,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { // `copyfile_state_free` returns -1 if the `to` or `from` files // cannot be closed. However, this is not considered this an // error. - copyfile_state_free(self.0); + libc::copyfile_state_free(self.0); } } } @@ -1896,6 +1976,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { // We store the availability in a global to avoid unnecessary syscalls static HAS_FCLONEFILEAT: AtomicBool = AtomicBool::new(true); syscall! { + // Mirrors `libc::fclonefileat` fn fclonefileat( srcfd: libc::c_int, dst_dirfd: libc::c_int, @@ -1932,22 +2013,22 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { // We ensure that `FreeOnDrop` never contains a null pointer so it is // always safe to call `copyfile_state_free` let state = unsafe { - let state = copyfile_state_alloc(); + let state = libc::copyfile_state_alloc(); if state.is_null() { return Err(crate::io::Error::last_os_error()); } FreeOnDrop(state) }; - let flags = if writer_metadata.is_file() { COPYFILE_ALL } else { COPYFILE_DATA }; + let flags = if writer_metadata.is_file() { COPYFILE_ALL } else { libc::COPYFILE_DATA }; - cvt(unsafe { fcopyfile(reader.as_raw_fd(), writer.as_raw_fd(), state.0, flags) })?; + cvt(unsafe { libc::fcopyfile(reader.as_raw_fd(), writer.as_raw_fd(), state.0, flags) })?; let mut bytes_copied: libc::off_t = 0; cvt(unsafe { - copyfile_state_get( + libc::copyfile_state_get( state.0, - COPYFILE_STATE_COPIED, + libc::COPYFILE_STATE_COPIED as u32, core::ptr::addr_of_mut!(bytes_copied) as *mut libc::c_void, ) })?; diff --git a/library/std/src/sys/pal/unix/fs/tests.rs b/library/std/src/sys/pal/unix/fs/tests.rs new file mode 100644 index 00000000000..71be3472148 --- /dev/null +++ b/library/std/src/sys/pal/unix/fs/tests.rs @@ -0,0 +1,71 @@ +use crate::sys::pal::unix::fs::FilePermissions; + +#[test] +fn test_debug_permissions() { + for (expected, mode) in [ + // typical directory + ("FilePermissions { mode: 0o040775 (drwxrwxr-x) }", 0o04_0775), + // typical text file + ("FilePermissions { mode: 0o100664 (-rw-rw-r--) }", 0o10_0664), + // setuid executable (/usr/bin/doas) + ("FilePermissions { mode: 0o104755 (-rwsr-xr-x) }", 0o10_4755), + // char device (/dev/zero) + ("FilePermissions { mode: 0o020666 (crw-rw-rw-) }", 0o02_0666), + // block device (/dev/vda) + ("FilePermissions { mode: 0o060660 (brw-rw----) }", 0o06_0660), + // symbolic link + ("FilePermissions { mode: 0o120777 (lrwxrwxrwx) }", 0o12_0777), + // fifo + ("FilePermissions { mode: 0o010664 (prw-rw-r--) }", 0o01_0664), + // none + ("FilePermissions { mode: 0o100000 (----------) }", 0o10_0000), + // unrecognized + ("FilePermissions { mode: 0o000001 }", 1), + ] { + assert_eq!(format!("{:?}", FilePermissions { mode }), expected); + } + + for (expected, mode) in [ + // owner readable + ("FilePermissions { mode: 0o100400 (-r--------) }", libc::S_IRUSR), + // owner writable + ("FilePermissions { mode: 0o100200 (--w-------) }", libc::S_IWUSR), + // owner executable + ("FilePermissions { mode: 0o100100 (---x------) }", libc::S_IXUSR), + // setuid + ("FilePermissions { mode: 0o104000 (---S------) }", libc::S_ISUID), + // owner executable and setuid + ("FilePermissions { mode: 0o104100 (---s------) }", libc::S_IXUSR | libc::S_ISUID), + // group readable + ("FilePermissions { mode: 0o100040 (----r-----) }", libc::S_IRGRP), + // group writable + ("FilePermissions { mode: 0o100020 (-----w----) }", libc::S_IWGRP), + // group executable + ("FilePermissions { mode: 0o100010 (------x---) }", libc::S_IXGRP), + // setgid + ("FilePermissions { mode: 0o102000 (------S---) }", libc::S_ISGID), + // group executable and setgid + ("FilePermissions { mode: 0o102010 (------s---) }", libc::S_IXGRP | libc::S_ISGID), + // other readable + ("FilePermissions { mode: 0o100004 (-------r--) }", libc::S_IROTH), + // other writeable + ("FilePermissions { mode: 0o100002 (--------w-) }", libc::S_IWOTH), + // other executable + ("FilePermissions { mode: 0o100001 (---------x) }", libc::S_IXOTH), + // sticky + ("FilePermissions { mode: 0o101000 (----------) }", libc::S_ISVTX), + // other executable and sticky + ("FilePermissions { mode: 0o101001 (---------x) }", libc::S_IXOTH | libc::S_ISVTX), + ] { + assert_eq!(format!("{:?}", FilePermissions { mode: libc::S_IFREG | mode }), expected); + } + + for (expected, mode) in [ + // restricted deletion ("sticky") flag is set, and search permission is not granted to others + ("FilePermissions { mode: 0o041000 (d--------T) }", libc::S_ISVTX), + // sticky and searchable + ("FilePermissions { mode: 0o041001 (d--------t) }", libc::S_ISVTX | libc::S_IXOTH), + ] { + assert_eq!(format!("{:?}", FilePermissions { mode: libc::S_IFDIR | mode }), expected); + } +} diff --git a/library/std/src/sys/pal/unsupported/process.rs b/library/std/src/sys/pal/unsupported/process.rs index 6a989dd3e76..2445d9073db 100644 --- a/library/std/src/sys/pal/unsupported/process.rs +++ b/library/std/src/sys/pal/unsupported/process.rs @@ -1,7 +1,6 @@ -use crate::ffi::OsStr; +use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::io; -use crate::marker::PhantomData; use crate::num::NonZero; use crate::path::Path; use crate::sys::fs::File; @@ -16,7 +15,14 @@ pub use crate::ffi::OsString as EnvKey; //////////////////////////////////////////////////////////////////////////////// pub struct Command { + program: OsString, + args: Vec<OsString>, env: CommandEnv, + + cwd: Option<OsString>, + stdin: Option<Stdio>, + stdout: Option<Stdio>, + stderr: Option<Stdio>, } // passed back to std::process with the pipes connected to the child, if any @@ -27,39 +33,62 @@ pub struct StdioPipes { pub stderr: Option<AnonPipe>, } -// FIXME: This should be a unit struct, so we can always construct it -// The value here should be never used, since we cannot spawn processes. +#[derive(Debug)] pub enum Stdio { Inherit, Null, MakePipe, + ParentStdout, + ParentStderr, + #[allow(dead_code)] // This variant exists only for the Debug impl + InheritFile(File), } impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } + pub fn new(program: &OsStr) -> Command { + Command { + program: program.to_owned(), + args: vec![program.to_owned()], + env: Default::default(), + cwd: None, + stdin: None, + stdout: None, + stderr: None, + } } - pub fn arg(&mut self, _arg: &OsStr) {} + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(arg.to_owned()); + } pub fn env_mut(&mut self) -> &mut CommandEnv { &mut self.env } - pub fn cwd(&mut self, _dir: &OsStr) {} + pub fn cwd(&mut self, dir: &OsStr) { + self.cwd = Some(dir.to_owned()); + } - pub fn stdin(&mut self, _stdin: Stdio) {} + pub fn stdin(&mut self, stdin: Stdio) { + self.stdin = Some(stdin); + } - pub fn stdout(&mut self, _stdout: Stdio) {} + pub fn stdout(&mut self, stdout: Stdio) { + self.stdout = Some(stdout); + } - pub fn stderr(&mut self, _stderr: Stdio) {} + pub fn stderr(&mut self, stderr: Stdio) { + self.stderr = Some(stderr); + } pub fn get_program(&self) -> &OsStr { - panic!("unsupported") + &self.program } pub fn get_args(&self) -> CommandArgs<'_> { - CommandArgs { _p: PhantomData } + let mut iter = self.args.iter(); + iter.next(); + CommandArgs { iter } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -67,7 +96,7 @@ impl Command { } pub fn get_current_dir(&self) -> Option<&Path> { - None + self.cwd.as_ref().map(|cs| Path::new(cs)) } pub fn spawn( @@ -91,31 +120,83 @@ impl From<AnonPipe> for Stdio { impl From<io::Stdout> for Stdio { fn from(_: io::Stdout) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + Stdio::ParentStdout } } impl From<io::Stderr> for Stdio { fn from(_: io::Stderr) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + Stdio::ParentStderr } } impl From<File> for Stdio { - fn from(_file: File) -> Stdio { - // FIXME: This is wrong. - // Instead, the Stdio we have here should be a unit struct. - panic!("unsupported") + fn from(file: File) -> Stdio { + Stdio::InheritFile(file) } } impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) + // show all attributes + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if f.alternate() { + let mut debug_command = f.debug_struct("Command"); + debug_command.field("program", &self.program).field("args", &self.args); + if !self.env.is_unchanged() { + debug_command.field("env", &self.env); + } + + if self.cwd.is_some() { + debug_command.field("cwd", &self.cwd); + } + + if self.stdin.is_some() { + debug_command.field("stdin", &self.stdin); + } + if self.stdout.is_some() { + debug_command.field("stdout", &self.stdout); + } + if self.stderr.is_some() { + debug_command.field("stderr", &self.stderr); + } + + debug_command.finish() + } else { + if let Some(ref cwd) = self.cwd { + write!(f, "cd {cwd:?} && ")?; + } + if self.env.does_clear() { + write!(f, "env -i ")?; + // Altered env vars will be printed next, that should exactly work as expected. + } else { + // Removed env vars need the command to be wrapped in `env`. + let mut any_removed = false; + for (key, value_opt) in self.get_envs() { + if value_opt.is_none() { + if !any_removed { + write!(f, "env ")?; + any_removed = true; + } + write!(f, "-u {} ", key.to_string_lossy())?; + } + } + } + // Altered env vars can just be added in front of the program. + for (key, value_opt) in self.get_envs() { + if let Some(value) = value_opt { + write!(f, "{}={value:?} ", key.to_string_lossy())?; + } + } + if self.program != self.args[0] { + write!(f, "[{:?}] ", self.program)?; + } + write!(f, "{:?}", self.args[0])?; + + for arg in &self.args[1..] { + write!(f, " {:?}", arg)?; + } + Ok(()) + } } } @@ -217,23 +298,30 @@ impl Process { } pub struct CommandArgs<'a> { - _p: PhantomData<&'a ()>, + iter: crate::slice::Iter<'a, OsString>, } impl<'a> Iterator for CommandArgs<'a> { type Item = &'a OsStr; fn next(&mut self) -> Option<&'a OsStr> { - None + self.iter.next().map(|os| &**os) } fn size_hint(&self) -> (usize, Option<usize>) { - (0, Some(0)) + self.iter.size_hint() } } -impl<'a> ExactSizeIterator for CommandArgs<'a> {} +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} impl<'a> fmt::Debug for CommandArgs<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().finish() + f.debug_list().entries(self.iter.clone()).finish() } } diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/pal/windows/args.rs index 2ecfe088d10..5098c05196e 100644 --- a/library/std/src/sys/pal/windows/args.rs +++ b/library/std/src/sys/pal/windows/args.rs @@ -7,7 +7,7 @@ mod tests; use super::os::current_exe; -use crate::ffi::OsString; +use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::io; use crate::num::NonZero; @@ -17,6 +17,7 @@ use crate::sys::path::get_long_path; use crate::sys::process::ensure_no_nuls; use crate::sys::{c, to_u16s}; use crate::sys_common::wstr::WStrUnits; +use crate::sys_common::AsInner; use crate::vec; use crate::iter; @@ -262,16 +263,92 @@ pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> i Ok(()) } +fn append_bat_arg(cmd: &mut Vec<u16>, arg: &OsStr, mut quote: bool) -> io::Result<()> { + ensure_no_nuls(arg)?; + // If an argument has 0 characters then we need to quote it to ensure + // that it actually gets passed through on the command line or otherwise + // it will be dropped entirely when parsed on the other end. + // + // We also need to quote the argument if it ends with `\` to guard against + // bat usage such as `"%~2"` (i.e. force quote arguments) otherwise a + // trailing slash will escape the closing quote. + if arg.is_empty() || arg.as_encoded_bytes().last() == Some(&b'\\') { + quote = true; + } + for cp in arg.as_inner().inner.code_points() { + if let Some(cp) = cp.to_char() { + // Rather than trying to find every ascii symbol that must be quoted, + // we assume that all ascii symbols must be quoted unless they're known to be good. + // We also quote Unicode control blocks for good measure. + // Note an unquoted `\` is fine so long as the argument isn't otherwise quoted. + static UNQUOTED: &str = r"#$*+-./:?@\_"; + let ascii_needs_quotes = + cp.is_ascii() && !(cp.is_ascii_alphanumeric() || UNQUOTED.contains(cp)); + if ascii_needs_quotes || cp.is_control() { + quote = true; + } + } + } + + if quote { + cmd.push('"' as u16); + } + // Loop through the string, escaping `\` only if followed by `"`. + // And escaping `"` by doubling them. + let mut backslashes: usize = 0; + for x in arg.encode_wide() { + if x == '\\' as u16 { + backslashes += 1; + } else { + if x == '"' as u16 { + // Add n backslashes to total 2n before internal `"`. + cmd.extend((0..backslashes).map(|_| '\\' as u16)); + // Appending an additional double-quote acts as an escape. + cmd.push(b'"' as u16) + } else if x == '%' as u16 || x == '\r' as u16 { + // yt-dlp hack: replaces `%` with `%%cd:~,%` to stop %VAR% being expanded as an environment variable. + // + // # Explanation + // + // cmd supports extracting a substring from a variable using the following syntax: + // %variable:~start_index,end_index% + // + // In the above command `cd` is used as the variable and the start_index and end_index are left blank. + // `cd` is a built-in variable that dynamically expands to the current directory so it's always available. + // Explicitly omitting both the start and end index creates a zero-length substring. + // + // Therefore it all resolves to nothing. However, by doing this no-op we distract cmd.exe + // from potentially expanding %variables% in the argument. + cmd.extend_from_slice(&[ + '%' as u16, '%' as u16, 'c' as u16, 'd' as u16, ':' as u16, '~' as u16, + ',' as u16, + ]); + } + backslashes = 0; + } + cmd.push(x); + } + if quote { + // Add n backslashes to total 2n before ending `"`. + cmd.extend((0..backslashes).map(|_| '\\' as u16)); + cmd.push('"' as u16); + } + Ok(()) +} + pub(crate) fn make_bat_command_line( script: &[u16], args: &[Arg], force_quotes: bool, ) -> io::Result<Vec<u16>> { + const INVALID_ARGUMENT_ERROR: io::Error = + io::const_io_error!(io::ErrorKind::InvalidInput, r#"batch file arguments are invalid"#); // Set the start of the command line to `cmd.exe /c "` // It is necessary to surround the command in an extra pair of quotes, // hence the trailing quote here. It will be closed after all arguments // have been added. - let mut cmd: Vec<u16> = "cmd.exe /d /c \"".encode_utf16().collect(); + // Using /e:ON enables "command extensions" which is essential for the `%` hack to work. + let mut cmd: Vec<u16> = "cmd.exe /e:ON /v:OFF /d /c \"".encode_utf16().collect(); // Push the script name surrounded by its quote pair. cmd.push(b'"' as u16); @@ -291,18 +368,22 @@ pub(crate) fn make_bat_command_line( // reconstructed by the batch script by default. for arg in args { cmd.push(' ' as u16); - // Make sure to always quote special command prompt characters, including: - // * Characters `cmd /?` says require quotes. - // * `%` for environment variables, as in `%TMP%`. - // * `|<>` pipe/redirect characters. - const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>"; - let force_quotes = match arg { - Arg::Regular(arg) if !force_quotes => { - arg.as_encoded_bytes().iter().any(|c| SPECIAL.contains(c)) + match arg { + Arg::Regular(arg_os) => { + let arg_bytes = arg_os.as_encoded_bytes(); + // Disallow \r and \n as they may truncate the arguments. + const DISALLOWED: &[u8] = b"\r\n"; + if arg_bytes.iter().any(|c| DISALLOWED.contains(c)) { + return Err(INVALID_ARGUMENT_ERROR); + } + append_bat_arg(&mut cmd, arg_os, force_quotes)?; + } + _ => { + // Raw arguments are passed on as-is. + // It's the user's responsibility to properly handle arguments in this case. + append_arg(&mut cmd, arg, force_quotes)?; } - _ => force_quotes, }; - append_arg(&mut cmd, arg, force_quotes)?; } // Close the quote we left opened earlier. diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index 7dcc1141099..a9cd26389cd 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -1,4 +1,4 @@ -//! OS-based thread local storage +//! OS-based thread local storage for non-Windows systems //! //! This module provides an implementation of OS-based thread local storage, //! using the native OS-provided facilities (think `TlsAlloc` or @@ -11,6 +11,9 @@ //! the OS-TLS key. The other is a type which does implement `Drop` and hence //! has a safe interface. //! +//! Windows doesn't use this module at all; `sys::pal::windows::thread_local_key` +//! gets imported in its stead. +//! //! # Usage //! //! This module should likely not be used directly unless other primitives are diff --git a/library/std/tests/process_spawning.rs b/library/std/tests/process_spawning.rs index 59f67f9901f..c56c111c37d 100644 --- a/library/std/tests/process_spawning.rs +++ b/library/std/tests/process_spawning.rs @@ -8,6 +8,7 @@ use std::str; mod common; #[test] +#[cfg_attr(miri, ignore)] // Process spawning not supported by Miri fn issue_15149() { // If we're the parent, copy our own binary to a new directory. let my_path = env::current_exe().unwrap(); diff --git a/library/std/tests/switch-stdout.rs b/library/std/tests/switch-stdout.rs index 27f3e8a9b96..0afe18088fa 100644 --- a/library/std/tests/switch-stdout.rs +++ b/library/std/tests/switch-stdout.rs @@ -51,6 +51,7 @@ fn switch_stdout_to(file: OwnedHandle) -> OwnedHandle { } #[test] +#[cfg_attr(miri, ignore)] // dup/SetStdHandle not supported by Miri fn switch_stdout() { let temp = common::tmpdir(); let path = temp.join("switch-stdout-output"); diff --git a/library/std/tests/thread.rs b/library/std/tests/thread.rs index 4ce81f2846e..79a981d0b0d 100644 --- a/library/std/tests/thread.rs +++ b/library/std/tests/thread.rs @@ -5,7 +5,8 @@ use std::time::Duration; #[test] #[cfg_attr(target_os = "emscripten", ignore)] -fn sleep() { +#[cfg_attr(miri, ignore)] // Miri does not like the thread leak +fn sleep_very_long() { let finished = Arc::new(Mutex::new(false)); let t_finished = finished.clone(); thread::spawn(move || { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 728c73d8c50..f3c22061d25 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -140,7 +140,10 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn>, options: Option<Opt }); panic::set_hook(hook); } - match console::run_tests_console(&opts, tests) { + let res = console::run_tests_console(&opts, tests); + // Prevent Valgrind from reporting reachable blocks in users' unit tests. + drop(panic::take_hook()); + match res { Ok(true) => {} Ok(false) => process::exit(ERROR_EXIT_CODE), Err(e) => { diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 0b67079917c..d6e60d52d63 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -52,6 +52,36 @@ check-aux: src/tools/cargo \ src/tools/cargotest \ $(BOOTSTRAP_ARGS) + # Run standard library tests in Miri. + # We use a 64bit little-endian and a 32bit big-endian target for max coverage. + $(Q)BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 \ + --target x86_64-unknown-linux-gnu,mips-unknown-linux-gnu \ + library/core \ + library/alloc \ + --no-doc + # Some doctests have intentional memory leaks. + # Also, they work only on the host. + $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" \ + $(BOOTSTRAP) miri --stage 2 \ + library/core \ + library/alloc \ + --doc + # In `std` we cannot test everything. + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 library/std \ + --no-doc -- \ + --skip fs:: --skip net:: --skip process:: --skip sys::pal:: + $(Q)MIRIFLAGS="-Zmiri-ignore-leaks -Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 library/std \ + --doc -- \ + --skip fs:: --skip net:: --skip process:: --skip sys::pal:: + # Also test some very target-specific modules on other targets. + $(Q)MIRIFLAGS="-Zmiri-disable-isolation" BOOTSTRAP_SKIP_TARGET_SANITY=1 \ + $(BOOTSTRAP) miri --stage 2 library/std \ + --target aarch64-apple-darwin,i686-pc-windows-gnu \ + --no-doc -- \ + time:: sync:: thread:: env:: dist: $(Q)$(BOOTSTRAP) dist $(BOOTSTRAP_ARGS) distcheck: diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index bacf5f0d33c..1e68f8d276a 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -597,7 +597,7 @@ impl Step for Miri { builder.ensure(compile::Std::new(target_compiler, host)); let host_sysroot = builder.sysroot(target_compiler); - // # Run `cargo test`. + // Run `cargo test`. // This is with the Miri crate, so it uses the host compiler. let mut cargo = tool::prepare_tool_cargo( builder, @@ -652,15 +652,46 @@ impl Step for Miri { builder.run(&mut cargo); } } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct CargoMiri { + target: TargetSelection, +} + +impl Step for CargoMiri { + type Output = (); + const ONLY_HOSTS: bool = false; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/miri/cargo-miri") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CargoMiri { target: run.target }); + } + + /// Tests `cargo miri test`. + fn run(self, builder: &Builder<'_>) { + let host = builder.build.build; + let target = self.target; + let stage = builder.top_stage; + if stage == 0 { + eprintln!("cargo-miri cannot be tested at stage 0"); + std::process::exit(1); + } - // # Run `cargo miri test`. + // This compiler runs on the host, we'll just use it for the target. + let compiler = builder.compiler(stage, host); + + // Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures // that we get the desired output), but that is sufficient to make sure that the libtest harness // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode. - // This is running the build `cargo-miri` for the given target, so we need the target compiler. let mut cargo = tool::prepare_tool_cargo( builder, - target_compiler, + compiler, Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test! target, "miri-test", @@ -2658,16 +2689,27 @@ impl Step for Crate { match mode { Mode::Std => { - compile::std_cargo(builder, target, compiler.stage, &mut cargo); - // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, - // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. - // Override it. - if builder.download_rustc() && compiler.stage > 0 { - let sysroot = builder - .out - .join(compiler.host.triple) - .join(format!("stage{}-test-sysroot", compiler.stage)); - cargo.env("RUSTC_SYSROOT", sysroot); + if builder.kind == Kind::Miri { + // We can't use `std_cargo` as that uses `optimized-compiler-builtins` which + // needs host tools for the given target. This is similar to what `compile::Std` + // does when `is_for_mir_opt_tests` is true. There's probably a chance for + // de-duplication here... `std_cargo` should support a mode that avoids needing + // host tools. + cargo + .arg("--manifest-path") + .arg(builder.src.join("library/sysroot/Cargo.toml")); + } else { + compile::std_cargo(builder, target, compiler.stage, &mut cargo); + // `std_cargo` actually does the wrong thing: it passes `--sysroot build/host/stage2`, + // but we want to use the force-recompile std we just built in `build/host/stage2-test-sysroot`. + // Override it. + if builder.download_rustc() && compiler.stage > 0 { + let sysroot = builder + .out + .join(compiler.host.triple) + .join(format!("stage{}-test-sysroot", compiler.stage)); + cargo.env("RUSTC_SYSROOT", sysroot); + } } } Mode::Rustc => { diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 9555be481e6..e3b27600c5e 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -645,27 +645,6 @@ pub enum Kind { } impl Kind { - pub fn parse(string: &str) -> Option<Kind> { - // these strings, including the one-letter aliases, must match the x.py help text - Some(match string { - "build" | "b" => Kind::Build, - "check" | "c" => Kind::Check, - "clippy" => Kind::Clippy, - "fix" => Kind::Fix, - "fmt" => Kind::Format, - "test" | "t" => Kind::Test, - "bench" => Kind::Bench, - "doc" | "d" => Kind::Doc, - "clean" => Kind::Clean, - "dist" => Kind::Dist, - "install" => Kind::Install, - "run" | "r" => Kind::Run, - "setup" => Kind::Setup, - "suggest" => Kind::Suggest, - _ => return None, - }) - } - pub fn as_str(&self) -> &'static str { match self { Kind::Build => "build", @@ -808,6 +787,7 @@ impl<'a> Builder<'a> { test::EditionGuide, test::Rustfmt, test::Miri, + test::CargoMiri, test::Clippy, test::RustDemangler, test::CompiletestTest, diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index bcb8260b15a..1a8322c0dfd 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -1911,15 +1911,6 @@ impl Compiler { pub fn is_snapshot(&self, build: &Build) -> bool { self.stage == 0 && self.host == build.build } - - /// Returns if this compiler should be treated as a final stage one in the - /// current build session. - /// This takes into account whether we're performing a full bootstrap or - /// not; don't directly compare the stage with `2`! - pub fn is_final_stage(&self, build: &Build) -> bool { - let final_stage = if build.config.full_bootstrap { 2 } else { 1 }; - self.stage >= final_stage - } } fn envify(s: &str) -> String { diff --git a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock index a579ea965f2..b0c17d9a296 100644 --- a/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock +++ b/src/ci/docker/host-x86_64/test-various/uefi_qemu_test/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "r-efi" -version = "4.3.0" +version = "4.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e244f96e03a3067f9e521d3167bd42657594cb8588c8d3a2db01545dc1af2e0" +checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" [[package]] name = "uefi_qemu_test" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index e08c4e1e8b7..a74db2250fc 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -25,5 +25,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh +# Miri is just too slow with full assertions +ENV NO_DEBUG_ASSERTIONS=1 +ENV NO_OVERFLOW_CHECKS=1 + ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu ENV RUST_CHECK_TARGET check-aux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index 6f720569898..a3e8f6176a3 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -78,16 +78,6 @@ ENV PATH="$NODE_FOLDER:${PATH}" COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ -# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries -# to create a new folder. For reference: -# https://github.com/puppeteer/puppeteer/issues/375 -# -# We also specify the version in case we need to update it to go around cache limitations. -# -# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case -# the local version of the package is different than the one used by the CI. -RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true - ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json \ @@ -100,6 +90,14 @@ COPY host-x86_64/dist-x86_64-linux/build-gccjit.sh /scripts/ RUN /scripts/build-gccjit.sh /scripts +# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries +# to create a new folder. For reference: +# https://github.com/puppeteer/puppeteer/issues/375 +# +# We also specify the version in case we need to update it to go around cache limitations. +# +# The `browser-ui-test.version` file is also used by bootstrap to emit warnings in case +# the local version of the package is different than the one used by the CI. ENV SCRIPT /tmp/checktools.sh ../x.py && \ - NODE_PATH=`npm root -g` python3 ../x.py test tests/rustdoc-gui --stage 2 \ - --test-args "'--no-sandbox --jobs 1'" + npm install browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true && \ + python3 ../x.py test tests/rustdoc-gui --stage 2 --test-args "'--no-sandbox --jobs 1'" diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index 14a8c245756..50c2e5e29f0 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.17.1 \ No newline at end of file +0.17.2 \ No newline at end of file diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh index 38c5b173ae3..53b4583166d 100755 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/checktools.sh @@ -32,9 +32,9 @@ python3 "$X_PY" test --stage 2 src/tools/rustfmt # that bugs which only surface when the GC runs at a specific time are more likely to cause CI to fail. # This significantly increases the runtime of our test suite, or we'd do this in PR CI too. if [ -z "${PR_CI_JOB:-}" ]; then - MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri + MIRIFLAGS=-Zmiri-provenance-gc=1 python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri else - python3 "$X_PY" test --stage 2 src/tools/miri + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri fi # We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc. # Also cover some other targets via cross-testing, in particular all tier 1 targets. @@ -42,8 +42,8 @@ case $HOST_TARGET in x86_64-unknown-linux-gnu) # Only this branch runs in PR CI. # Fully test all main OSes, including a 32bit target. - python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-apple-darwin - python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target x86_64-apple-darwin + python3 "$X_PY" test --stage 2 src/tools/miri src/tools/miri/cargo-miri --target i686-pc-windows-msvc # Only run "pass" tests for the remaining targets, which is quite a bit faster. python3 "$X_PY" test --stage 2 src/tools/miri --target x86_64-pc-windows-gnu --test-args pass python3 "$X_PY" test --stage 2 src/tools/miri --target i686-unknown-linux-gnu --test-args pass diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 80e23574404..9323bb093ad 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -249,7 +249,8 @@ x--expand-yaml-anchors--remove: <<: *step - name: run the build - run: src/ci/scripts/run-build-from-ci.sh + # Redirect stderr to stdout to avoid reordering the two streams in the GHA logs. + run: src/ci/scripts/run-build-from-ci.sh 2>&1 env: AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }} diff --git a/src/doc/book b/src/doc/book -Subproject 19c40bfd2d57641d962f3119a1c343355f1b3c5 +Subproject 3131aa4642c627a24f523c82566b94a7d920f68 diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 98b33e9a441457b0a491fe1be90e7de64eafc3e +Subproject eb3eb80e106d03250c1fb7c5666b1c8c5967286 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject 2e95fc2fd31d669947e993aa07ef10dc9828bee +Subproject aa7d4b0b4653ddb47cb1de2036d090ec2ba9dab diff --git a/src/doc/nomicon b/src/doc/nomicon -Subproject 6bc2415218d4dd0cb01433d8320f5ccf79c343a +Subproject 0d5f88475fe285affa6dbbc806e9e44d730797c diff --git a/src/doc/reference b/src/doc/reference -Subproject 984b36eca4b9293df04d5ba4eb5c4f77db0f51d +Subproject 55694913b1301cc809f9bf4a1ad1b3d6920efbd diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 7601e0c5ad29d5bd3b518700ea63fddfff5915a +Subproject 60d34b5fd33db1346f9aabfc0c9d0bda6c8e42b diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject ffa246b7fd95a96e1cd54883e613aed42c32547 +Subproject b77a34bd46399687b4ce6a17198e9f316c98879 diff --git a/src/doc/unstable-book/src/compiler-flags/check-cfg.md b/src/doc/unstable-book/src/compiler-flags/check-cfg.md index 13027eeaf4f..90a006b0a1e 100644 --- a/src/doc/unstable-book/src/compiler-flags/check-cfg.md +++ b/src/doc/unstable-book/src/compiler-flags/check-cfg.md @@ -77,7 +77,7 @@ Those well known names and values follows the same stability as what they refer Well known names and values checking is always enabled as long as at least one `--check-cfg` argument is present. -As of `2024-02-15T`, the list of known names is as follows: +As of `2024-04-06T`, the list of known names is as follows: <!--- See CheckCfg::fill_well_known in compiler/rustc_session/src/config.rs --> @@ -107,6 +107,7 @@ As of `2024-02-15T`, the list of known names is as follows: - `target_thread_local` - `target_vendor` - `test` + - `ub_checks` - `unix` - `windows` diff --git a/src/doc/unstable-book/src/compiler-flags/ub-checks.md b/src/doc/unstable-book/src/compiler-flags/ub-checks.md new file mode 100644 index 00000000000..528c868d7ad --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/ub-checks.md @@ -0,0 +1,17 @@ +# `ub-checks` + +The tracking issue for this feature is: [#123499](https://github.com/rust-lang/rust/issues/123499). + +-------------------- + +The `-Zub-checks` compiler flag enables additional runtime checks that detect some causes of Undefined Behavior at runtime. +By default, `-Zub-checks` flag inherits the value of `-Cdebug-assertions`. + +All checks are generated on a best-effort basis; even if we have a check implemented for some cause of Undefined Behavior, it may be possible for the check to not fire. +If a dependency is compiled with `-Zub-checks=no` but the final binary or library is compiled with `-Zub-checks=yes`, UB checks reached by the dependency are likely to be optimized out. + +When `-Zub-checks` detects UB, a non-unwinding panic is produced. +That means that we will not unwind the stack and will not call any `Drop` impls, but we will execute the configured panic hook. +We expect that unsafe code has been written which relies on code not unwinding which may have UB checks inserted. +Ergo, an unwinding panic could easily turn works-as-intended UB into a much bigger problem. +Calling the panic hook theoretically has the same implications, but we expect that the standard library panic hook will be stateless enough to be always called, and that if a user has configured a panic hook that the hook may be very helpful to debugging the detected UB. diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 217f6bb550b..daf63998461 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -168,7 +168,7 @@ fn clean_param_env<'tcx>( // FIXME(#111101): Incorporate the explicit predicates of the item here... let item_predicates: FxIndexSet<_> = - tcx.predicates_of(item_def_id).predicates.iter().map(|(pred, _)| pred).collect(); + tcx.param_env(item_def_id).caller_bounds().iter().collect(); let where_predicates = param_env .caller_bounds() .iter() diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 72d4cc7c465..8ed6ee014f3 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -1,141 +1,130 @@ -use crate::rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_hir as hir; use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt}; use rustc_infer::traits; -use rustc_middle::ty::ToPredicate; +use rustc_middle::ty::{self, ToPredicate}; +use rustc_span::def_id::DefId; use rustc_span::DUMMY_SP; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use super::*; +use thin_vec::ThinVec; -pub(crate) struct BlanketImplFinder<'a, 'tcx> { - pub(crate) cx: &'a mut core::DocContext<'tcx>, -} +use crate::clean; +use crate::clean::{ + clean_middle_assoc_item, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty_generics, +}; +use crate::core::DocContext; + +#[instrument(level = "debug", skip(cx))] +pub(crate) fn synthesize_blanket_impls( + cx: &mut DocContext<'_>, + item_def_id: DefId, +) -> Vec<clean::Item> { + let tcx = cx.tcx; + let ty = tcx.type_of(item_def_id); -impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { - pub(crate) fn get_blanket_impls(&mut self, item_def_id: DefId) -> Vec<Item> { - let cx = &mut self.cx; - let ty = cx.tcx.type_of(item_def_id); + let mut blanket_impls = Vec::new(); + for trait_def_id in tcx.all_traits() { + if !cx.cache.effective_visibilities.is_reachable(tcx, trait_def_id) + || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some() + { + continue; + } + // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls + let trait_impls = tcx.trait_impls_of(trait_def_id); + 'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() { + trace!("considering impl `{impl_def_id:?}` for trait `{trait_def_id:?}`"); - trace!("get_blanket_impls({ty:?})"); - let mut impls = Vec::new(); - for trait_def_id in cx.tcx.all_traits() { - if !cx.cache.effective_visibilities.is_reachable(cx.tcx, trait_def_id) - || cx.generated_synthetics.get(&(ty.skip_binder(), trait_def_id)).is_some() - { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { continue; } - // NOTE: doesn't use `for_each_relevant_impl` to avoid looking at anything besides blanket impls - let trait_impls = cx.tcx.trait_impls_of(trait_def_id); - 'blanket_impls: for &impl_def_id in trait_impls.blanket_impls() { - trace!( - "get_blanket_impls: Considering impl for trait '{:?}' {:?}", - trait_def_id, - impl_def_id - ); - let trait_ref = cx.tcx.impl_trait_ref(impl_def_id).unwrap(); - if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { - continue; - } - let infcx = cx.tcx.infer_ctxt().build(); - let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id); - let impl_ty = ty.instantiate(infcx.tcx, args); - let param_env = ty::ParamEnv::empty(); + let infcx = tcx.infer_ctxt().build(); + let args = infcx.fresh_args_for_item(DUMMY_SP, item_def_id); + let impl_ty = ty.instantiate(tcx, args); + let param_env = ty::ParamEnv::empty(); - let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); - let impl_trait_ref = trait_ref.instantiate(infcx.tcx, impl_args); + let impl_args = infcx.fresh_args_for_item(DUMMY_SP, impl_def_id); + let impl_trait_ref = trait_ref.instantiate(tcx, impl_args); - // Require the type the impl is implemented on to match - // our type, and ignore the impl if there was a mismatch. - let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq( - DefineOpaqueTypes::Yes, - impl_trait_ref.self_ty(), - impl_ty, - ) else { - continue; - }; - let InferOk { value: (), obligations } = eq_result; - // FIXME(eddyb) ignoring `obligations` might cause false positives. - drop(obligations); + // Require the type the impl is implemented on to match + // our type, and ignore the impl if there was a mismatch. + let Ok(eq_result) = infcx.at(&traits::ObligationCause::dummy(), param_env).eq( + DefineOpaqueTypes::Yes, + impl_trait_ref.self_ty(), + impl_ty, + ) else { + continue; + }; + let InferOk { value: (), obligations } = eq_result; + // FIXME(eddyb) ignoring `obligations` might cause false positives. + drop(obligations); - trace!( - "invoking predicate_may_hold: param_env={:?}, impl_trait_ref={:?}, impl_ty={:?}", + let predicates = tcx + .predicates_of(impl_def_id) + .instantiate(tcx, impl_args) + .predicates + .into_iter() + .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(tcx))); + for predicate in predicates { + let obligation = traits::Obligation::new( + tcx, + traits::ObligationCause::dummy(), param_env, - impl_trait_ref, - impl_ty + predicate, ); - let predicates = cx - .tcx - .predicates_of(impl_def_id) - .instantiate(cx.tcx, impl_args) - .predicates - .into_iter() - .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(infcx.tcx))); - for predicate in predicates { - debug!("testing predicate {predicate:?}"); - let obligation = traits::Obligation::new( - infcx.tcx, - traits::ObligationCause::dummy(), - param_env, - predicate, - ); - match infcx.evaluate_obligation(&obligation) { - Ok(eval_result) if eval_result.may_apply() => {} - Err(traits::OverflowError::Canonical) => {} - _ => continue 'blanket_impls, - } + match infcx.evaluate_obligation(&obligation) { + Ok(eval_result) if eval_result.may_apply() => {} + Err(traits::OverflowError::Canonical) => {} + _ => continue 'blanket_impls, } - debug!( - "get_blanket_impls: found applicable impl for trait_ref={:?}, ty={:?}", - trait_ref, ty - ); + } + debug!("found applicable impl for trait ref {trait_ref:?}"); - cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id)); + cx.generated_synthetics.insert((ty.skip_binder(), trait_def_id)); - impls.push(Item { - name: None, - attrs: Default::default(), - item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, - kind: Box::new(ImplItem(Box::new(Impl { - unsafety: hir::Unsafety::Normal, - generics: clean_ty_generics( - cx, - cx.tcx.generics_of(impl_def_id), - cx.tcx.explicit_predicates_of(impl_def_id), - ), - // FIXME(eddyb) compute both `trait_` and `for_` from - // the post-inference `trait_ref`, as it's more accurate. - trait_: Some(clean_trait_ref_with_bindings( - cx, - ty::Binder::dummy(trait_ref.instantiate_identity()), - ThinVec::new(), - )), - for_: clean_middle_ty( - ty::Binder::dummy(ty.instantiate_identity()), - cx, - None, - None, - ), - items: cx - .tcx - .associated_items(impl_def_id) - .in_definition_order() - .filter(|item| !item.is_impl_trait_in_trait()) - .map(|item| clean_middle_assoc_item(item, cx)) - .collect::<Vec<_>>(), - polarity: ty::ImplPolarity::Positive, - kind: ImplKind::Blanket(Box::new(clean_middle_ty( - ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()), - cx, - None, - None, - ))), - }))), - cfg: None, - inline_stmt_id: None, - }); - } + blanket_impls.push(clean::Item { + name: None, + attrs: Default::default(), + item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id }, + kind: Box::new(clean::ImplItem(Box::new(clean::Impl { + unsafety: hir::Unsafety::Normal, + generics: clean_ty_generics( + cx, + tcx.generics_of(impl_def_id), + tcx.explicit_predicates_of(impl_def_id), + ), + // FIXME(eddyb) compute both `trait_` and `for_` from + // the post-inference `trait_ref`, as it's more accurate. + trait_: Some(clean_trait_ref_with_bindings( + cx, + ty::Binder::dummy(trait_ref.instantiate_identity()), + ThinVec::new(), + )), + for_: clean_middle_ty( + ty::Binder::dummy(ty.instantiate_identity()), + cx, + None, + None, + ), + items: tcx + .associated_items(impl_def_id) + .in_definition_order() + .filter(|item| !item.is_impl_trait_in_trait()) + .map(|item| clean_middle_assoc_item(item, cx)) + .collect(), + polarity: ty::ImplPolarity::Positive, + kind: clean::ImplKind::Blanket(Box::new(clean_middle_ty( + ty::Binder::dummy(trait_ref.instantiate_identity().self_ty()), + cx, + None, + None, + ))), + }))), + cfg: None, + inline_stmt_id: None, + }); } - - impls } + + blanket_impls } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index a25a506d9c5..12f45fe4979 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -29,7 +29,7 @@ use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::hygiene::{AstPass, MacroKind}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{self, ExpnKind}; +use rustc_span::ExpnKind; use rustc_trait_selection::traits::wf::object_region_bounds; use std::borrow::Cow; @@ -37,14 +37,14 @@ use std::collections::BTreeMap; use std::mem; use thin_vec::ThinVec; -use crate::core::{self, DocContext}; +use crate::core::DocContext; use crate::formats::item_type::ItemType; use crate::visit_ast::Module as DocModule; use utils::*; pub(crate) use self::types::*; -pub(crate) use self::utils::{get_auto_trait_and_blanket_impls, krate, register_res}; +pub(crate) use self::utils::{krate, register_res, synthesize_auto_trait_and_blanket_impls}; pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item { let mut items: Vec<Item> = vec![]; @@ -1782,6 +1782,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T BorrowedRef { lifetime, mutability: m.mutbl, type_: Box::new(clean_ty(m.ty, cx)) } } TyKind::Slice(ty) => Slice(Box::new(clean_ty(ty, cx))), + TyKind::Pat(ty, pat) => Type::Pat(Box::new(clean_ty(ty, cx)), format!("{pat:?}").into()), TyKind::Array(ty, ref length) => { let length = match length { hir::ArrayLen::Infer(..) => "_".to_string(), @@ -2008,6 +2009,10 @@ pub(crate) fn clean_middle_ty<'tcx>( ty::Float(float_ty) => Primitive(float_ty.into()), ty::Str => Primitive(PrimitiveType::Str), ty::Slice(ty) => Slice(Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None))), + ty::Pat(ty, pat) => Type::Pat( + Box::new(clean_middle_ty(bound_ty.rebind(ty), cx, None, None)), + format!("{pat:?}").into_boxed_str(), + ), ty::Array(ty, mut n) => { n = n.normalize(cx.tcx, ty::ParamEnv::reveal_all()); let n = print_const(cx, n); diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 6793ea9f485..b592bd76e4c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -23,6 +23,7 @@ use rustc_hir::{BodyId, Mutability}; use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety; use rustc_index::IndexVec; use rustc_metadata::rendered_const; +use rustc_middle::span_bug; use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_resolve::rustdoc::{ @@ -266,8 +267,15 @@ impl ExternalCrate { let as_primitive = |res: Res<!>| { let Res::Def(DefKind::Mod, def_id) = res else { return None }; tcx.get_attrs(def_id, sym::rustc_doc_primitive).find_map(|attr| { - // FIXME: should warn on unknown primitives? - Some((def_id, PrimitiveType::from_symbol(attr.value_str()?)?)) + let attr_value = attr.value_str().expect("syntax should already be validated"); + let Some(prim) = PrimitiveType::from_symbol(attr_value) else { + span_bug!( + attr.span, + "primitive `{attr_value}` is not a member of `PrimitiveType`" + ); + }; + + Some((def_id, prim)) }) }; @@ -1475,7 +1483,9 @@ pub(crate) enum Type { /// /// This is mostly Rustdoc's version of [`hir::Path`]. /// It has to be different because Rustdoc's [`PathSegment`] can contain cleaned generics. - Path { path: Path }, + Path { + path: Path, + }, /// A `dyn Trait` object: `dyn for<'a> Trait<'a> + Send + 'static` DynTrait(Vec<PolyTrait>, Option<Lifetime>), /// A type parameter. @@ -1492,10 +1502,15 @@ pub(crate) enum Type { /// /// The `String` field is a stringified version of the array's length parameter. Array(Box<Type>, Box<str>), + Pat(Box<Type>, Box<str>), /// A raw pointer type: `*const i32`, `*mut i32` RawPointer(Mutability, Box<Type>), /// A reference type: `&i32`, `&'a mut Foo` - BorrowedRef { lifetime: Option<Lifetime>, mutability: Mutability, type_: Box<Type> }, + BorrowedRef { + lifetime: Option<Lifetime>, + mutability: Mutability, + type_: Box<Type>, + }, /// A qualified path to an associated item: `<Type as Trait>::Name` QPath(Box<QPathData>), @@ -1692,6 +1707,7 @@ impl Type { BareFunction(..) => PrimitiveType::Fn, Slice(..) => PrimitiveType::Slice, Array(..) => PrimitiveType::Array, + Type::Pat(..) => PrimitiveType::Pat, RawPointer(..) => PrimitiveType::RawPointer, QPath(box QPathData { ref self_type, .. }) => return self_type.inner_def_id(cache), Generic(_) | Infer | ImplTrait(_) => return None, @@ -1745,6 +1761,7 @@ pub(crate) enum PrimitiveType { Str, Slice, Array, + Pat, Tuple, Unit, RawPointer, @@ -1797,8 +1814,10 @@ impl PrimitiveType { sym::bool => Some(PrimitiveType::Bool), sym::char => Some(PrimitiveType::Char), sym::str => Some(PrimitiveType::Str), + sym::f16 => Some(PrimitiveType::F16), sym::f32 => Some(PrimitiveType::F32), sym::f64 => Some(PrimitiveType::F64), + sym::f128 => Some(PrimitiveType::F128), sym::array => Some(PrimitiveType::Array), sym::slice => Some(PrimitiveType::Slice), sym::tuple => Some(PrimitiveType::Tuple), @@ -1831,8 +1850,10 @@ impl PrimitiveType { U32 => single(SimplifiedType::Uint(UintTy::U32)), U64 => single(SimplifiedType::Uint(UintTy::U64)), U128 => single(SimplifiedType::Uint(UintTy::U128)), + F16 => single(SimplifiedType::Float(FloatTy::F16)), F32 => single(SimplifiedType::Float(FloatTy::F32)), F64 => single(SimplifiedType::Float(FloatTy::F64)), + F128 => single(SimplifiedType::Float(FloatTy::F128)), Str => single(SimplifiedType::Str), Bool => single(SimplifiedType::Bool), Char => single(SimplifiedType::Char), @@ -1895,6 +1916,7 @@ impl PrimitiveType { Bool => sym::bool, Char => sym::char, Array => sym::array, + Pat => sym::pat, Slice => sym::slice, Tuple => sym::tuple, Unit => sym::unit, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index d5e0e83696f..dc62fbb5edb 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -1,5 +1,5 @@ use crate::clean::auto_trait::synthesize_auto_trait_impls; -use crate::clean::blanket_impl::BlanketImplFinder; +use crate::clean::blanket_impl::synthesize_blanket_impls; use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate, @@ -477,8 +477,7 @@ pub(crate) fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type { } } -// FIXME(fmease): Update the `get_*` terminology to the `synthesize_` one. -pub(crate) fn get_auto_trait_and_blanket_impls( +pub(crate) fn synthesize_auto_trait_and_blanket_impls( cx: &mut DocContext<'_>, item_def_id: DefId, ) -> impl Iterator<Item = Item> { @@ -490,8 +489,8 @@ pub(crate) fn get_auto_trait_and_blanket_impls( let blanket_impls = cx .sess() .prof - .generic_activity("get_blanket_impls") - .run(|| BlanketImplFinder { cx }.get_blanket_impls(item_def_id)); + .generic_activity("synthesize_blanket_impls") + .run(|| synthesize_blanket_impls(cx, item_def_id)); auto_impls.into_iter().chain(blanket_impls) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 312765d3e6d..f82b89fdd5f 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1071,6 +1071,10 @@ fn fmt_type<'cx>( write!(f, "]") } }, + clean::Type::Pat(ref t, ref pat) => { + fmt::Display::fmt(&t.print(cx), f)?; + write!(f, " is {pat}") + } clean::Array(ref t, ref n) => match **t { clean::Generic(name) if !f.alternate() => primitive_link( f, diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs index 51f90e45500..7083999de68 100644 --- a/src/librustdoc/html/render/search_index.rs +++ b/src/librustdoc/html/render/search_index.rs @@ -668,7 +668,7 @@ fn get_index_type_id( } } // Not supported yet - clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None, + clean::Type::Pat(..) | clean::Generic(_) | clean::ImplTrait(_) | clean::Infer => None, } } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index cb50a27326f..35b99ab46f0 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -573,6 +573,10 @@ impl FromWithTcx<clean::Type> for Type { Tuple(t) => Type::Tuple(t.into_tcx(tcx)), Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))), Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() }, + clean::Type::Pat(t, p) => Type::Pat { + type_: Box::new((*t).into_tcx(tcx)), + __pat_unstable_do_not_use: p.to_string(), + }, ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)), Infer => Type::Infer, RawPointer(mutability, type_) => Type::RawPointer { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a5c26429013..1ba4e6cbdf0 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -491,6 +491,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ty::Str => Res::Primitive(Str), ty::Tuple(tys) if tys.is_empty() => Res::Primitive(Unit), ty::Tuple(_) => Res::Primitive(Tuple), + ty::Pat(..) => Res::Primitive(Pat), ty::Array(..) => Res::Primitive(Array), ty::Slice(_) => Res::Primitive(Slice), ty::RawPtr(_, _) => Res::Primitive(RawPointer), @@ -536,8 +537,10 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { I64 => tcx.types.i64, I128 => tcx.types.i128, Isize => tcx.types.isize, + F16 => tcx.types.f16, F32 => tcx.types.f32, F64 => tcx.types.f64, + F128 => tcx.types.f128, U8 => tcx.types.u8, U16 => tcx.types.u16, U32 => tcx.types.u32, @@ -2196,8 +2199,10 @@ fn resolve_primitive(path_str: &str, ns: Namespace) -> Option<Res> { "u32" => U32, "u64" => U64, "u128" => U128, + "f16" => F16, "f32" => F32, "f64" => F64, + "f128" => F128, "char" => Char, "bool" | "true" | "false" => Bool, "str" | "&str" => Str, diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index fbbb6152cfe..c92cf9d3e80 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -122,7 +122,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> _ => true, } }) { - let impls = get_auto_trait_and_blanket_impls(cx, def_id); + let impls = synthesize_auto_trait_and_blanket_impls(cx, def_id); new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id))); } } @@ -230,8 +230,10 @@ impl<'a, 'tcx> DocVisitor for SyntheticImplCollector<'a, 'tcx> { if i.is_struct() || i.is_enum() || i.is_union() { // FIXME(eddyb) is this `doc(hidden)` check needed? if !self.cx.tcx.is_doc_hidden(i.item_id.expect_def_id()) { - self.impls - .extend(get_auto_trait_and_blanket_impls(self.cx, i.item_id.expect_def_id())); + self.impls.extend(synthesize_auto_trait_and_blanket_impls( + self.cx, + i.item_id.expect_def_id(), + )); } } diff --git a/src/llvm-project b/src/llvm-project -Subproject 0af6c732ec6ca189cd7725e4a7d4290793046e8 +Subproject af8f9eb61a2ad4ee1f2d3f46d157b93a47c6a4b diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 164f88faa31..89d6f8d67f1 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use std::path::PathBuf; /// rustdoc format-version. -pub const FORMAT_VERSION: u32 = 28; +pub const FORMAT_VERSION: u32 = 29; /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information /// about the language items in the local crate, as well as info about external items to allow @@ -562,6 +562,13 @@ pub enum Type { type_: Box<Type>, len: String, }, + /// `u32 is 1..` + Pat { + #[serde(rename = "type")] + type_: Box<Type>, + #[doc(hidden)] + __pat_unstable_do_not_use: String, + }, /// `impl TraitA + TraitB + ...` ImplTrait(Vec<GenericBound>), /// `_` diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 0637083df5bbdcc951845f0d2eff6999cdb6d30 +Subproject 28e7b2bc0a812f90126be30f48a00a4ada990ea diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 560b2acc1c7..f83fb1b9019 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -821,6 +821,7 @@ impl TyCoercionStability { | TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) + | TyKind::Pat(..) | TyKind::Never | TyKind::Tup(_) | TyKind::Path(_) => Self::Deref, @@ -869,6 +870,7 @@ impl TyCoercionStability { | ty::Int(_) | ty::Uint(_) | ty::Array(..) + | ty::Pat(..) | ty::Float(_) | ty::RawPtr(..) | ty::FnPtr(_) diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index a60a40a2a47..2bb63ec2b04 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -294,8 +294,7 @@ fn elision_suggestions( let span = cx .sess() .source_map() - .span_extend_while(usage.ident.span, |ch| ch.is_ascii_whitespace()) - .unwrap_or(usage.ident.span); + .span_extend_while_whitespace(usage.ident.span); (span, String::new()) }, diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs index 23fc323446e..d3347466be9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs @@ -12,7 +12,6 @@ use rustc_errors::Applicability; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node}; -use rustc_hir_typeck::{FnCtxt, TypeckRootCtxt}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; use rustc_middle::mir::Mutability; @@ -437,9 +436,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Item(item) => { if let ItemKind::Fn(_, _, body_id) = &item.kind && let output_ty = return_ty(cx, item.owner_id) - && let root_ctxt = TypeckRootCtxt::new(cx.tcx, item.owner_id.def_id) - && let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, item.owner_id.def_id) - && fn_ctxt.can_coerce(ty, output_ty) + && rustc_hir_typeck::can_coerce(cx.tcx, cx.param_env, item.owner_id.def_id, ty, output_ty) { if has_lifetime(output_ty) && has_lifetime(ty) { return false; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index f5ce8dd29b1..3cf054e7207 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -66,7 +66,7 @@ declare_clippy_lint! { /// /// ### Known problems /// The lint does not work properly with desugaring and - /// macro, it has been allowed in the mean time. + /// macro, it has been allowed in the meantime. /// /// ### Example /// ```no_run diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs index 6f5ac625e35..a6a6e9a3bac 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs @@ -1,4 +1,4 @@ -use super::utils::check_cast; +use rustc_hir_typeck::cast::check_cast; use super::TRANSMUTES_EXPRESSIBLE_AS_PTR_CASTS; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; @@ -22,7 +22,7 @@ pub(super) fn check<'tcx>( ) -> bool { use CastKind::{AddrPtrCast, ArrayPtrCast, FnPtrAddrCast, FnPtrPtrCast, PtrAddrCast, PtrPtrCast}; let mut app = Applicability::MachineApplicable; - let mut sugg = match check_cast(cx, e, from_ty, to_ty) { + let mut sugg = match check_cast(cx.tcx, cx.param_env, e, from_ty, to_ty) { Some(FnPtrAddrCast | PtrAddrCast) if const_context => return false, Some(PtrPtrCast | AddrPtrCast | ArrayPtrCast | FnPtrPtrCast | FnPtrAddrCast) => { Sugg::hir_with_context(cx, arg, e.span.ctxt(), "..", &mut app) diff --git a/src/tools/clippy/clippy_lints/src/transmute/utils.rs b/src/tools/clippy/clippy_lints/src/transmute/utils.rs index 15f1890aa39..e8ccd35b4da 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/utils.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/utils.rs @@ -1,10 +1,5 @@ -use rustc_hir as hir; -use rustc_hir::Expr; -use rustc_hir_typeck::{cast, FnCtxt, TypeckRootCtxt}; use rustc_lint::LateContext; -use rustc_middle::ty::cast::CastKind; use rustc_middle::ty::Ty; -use rustc_span::DUMMY_SP; // check if the component types of the transmuted collection and the result have different ABI, // size or alignment @@ -20,35 +15,3 @@ pub(super) fn is_layout_incompatible<'tcx>(cx: &LateContext<'tcx>, from: Ty<'tcx false } } - -/// If a cast from `from_ty` to `to_ty` is valid, returns an Ok containing the kind of -/// the cast. In certain cases, including some invalid casts from array references -/// to pointers, this may cause additional errors to be emitted and/or ICE error -/// messages. This function will panic if that occurs. -pub(super) fn check_cast<'tcx>( - cx: &LateContext<'tcx>, - e: &'tcx Expr<'_>, - from_ty: Ty<'tcx>, - to_ty: Ty<'tcx>, -) -> Option<CastKind> { - let hir_id = e.hir_id; - let local_def_id = hir_id.owner.def_id; - - let root_ctxt = TypeckRootCtxt::new(cx.tcx, local_def_id); - let fn_ctxt = FnCtxt::new(&root_ctxt, cx.param_env, local_def_id); - - if let Ok(check) = cast::CastCheck::new( - &fn_ctxt, - e, - from_ty, - to_ty, - // We won't show any error to the user, so we don't care what the span is here. - DUMMY_SP, - DUMMY_SP, - hir::Constness::NotConst, - ) { - check.do_check(&fn_ctxt).ok() - } else { - None - } -} diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index f8bbe997774..6c3d9329932 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1068,6 +1068,10 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty(ty); self.hash_array_length(len); }, + TyKind::Pat(ty, pat) => { + self.hash_ty(ty); + self.hash_pat(pat); + }, TyKind::Ptr(ref mut_ty) => { self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index b84f4e87e07..763ce59ba1d 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -4,7 +4,7 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: the compiler unexpectedly panicked. this is a bug. -note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the mean time +note: it seems that this compiler <version> is outdated, a newer nightly should have been released in the meantime | = note: please consider running `rustup update nightly` to update the nightly channel and check if this problem still persists = note: if the problem still persists, we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index e414bc384f1..ec944cb7fb4 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -266,7 +266,7 @@ impl TestProps { aux_crates: vec![], revisions: vec![], rustc_env: vec![("RUSTC_ICE".to_string(), "0".to_string())], - unset_rustc_env: vec![], + unset_rustc_env: vec![("RUSTC_LOG_COLOR".to_string())], exec_env: vec![], unset_exec_env: vec![], build_aux_docs: false, @@ -819,6 +819,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "needs-dynamic-linking", "needs-git-hash", "needs-llvm-components", + "needs-matching-clang", "needs-profiler-support", "needs-relocation-model-pic", "needs-run-enabled", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 689fdc5dfeb..327e34ea36b 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -752,6 +752,19 @@ impl<'test> TestCx<'test> { Lazy::new(|| Regex::new(r"(?m:^)(?<prefix>(?: \|)+ Branch \()[0-9]+:").unwrap()); let coverage = BRANCH_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:"); + // ` |---> MC/DC Decision Region (1:30) to (2:` => ` |---> MC/DC Decision Region (LL:30) to (LL:` + static MCDC_DECISION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| { + Regex::new(r"(?m:^)(?<prefix>(?: \|)+---> MC/DC Decision Region \()[0-9]+:(?<middle>[0-9]+\) to \()[0-9]+:").unwrap() + }); + let coverage = + MCDC_DECISION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:${middle}LL:"); + + // ` | Condition C1 --> (1:` => ` | Condition C1 --> (LL:` + static MCDC_CONDITION_LINE_NUMBER_RE: Lazy<Regex> = Lazy::new(|| { + Regex::new(r"(?m:^)(?<prefix>(?: \|)+ Condition C[0-9]+ --> \()[0-9]+:").unwrap() + }); + let coverage = MCDC_CONDITION_LINE_NUMBER_RE.replace_all(&coverage, "${prefix}LL:"); + coverage.into_owned() } @@ -2354,6 +2367,11 @@ impl<'test> TestCx<'test> { "ignore-directory-in-diagnostics-source-blocks={}", home::cargo_home().expect("failed to find cargo home").to_str().unwrap() )); + // Similarly, vendored sources shouldn't be shown when running from a dist tarball. + rustc.arg("-Z").arg(format!( + "ignore-directory-in-diagnostics-source-blocks={}", + self.config.find_rust_src_root().unwrap().join("vendor").display(), + )); // Optionally prevent default --sysroot if specified in test compile-flags. if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) @@ -4252,7 +4270,7 @@ impl<'test> TestCx<'test> { if self.props.run_rustfix && self.config.compare_mode.is_none() { // And finally, compile the fixed code and make sure it both // succeeds and has no diagnostics. - let rustc = self.make_compile_args( + let mut rustc = self.make_compile_args( &self.expected_output_path(UI_FIXED), TargetLocation::ThisFile(self.make_exe_name()), emit_metadata, @@ -4260,6 +4278,26 @@ impl<'test> TestCx<'test> { LinkToAux::Yes, Vec::new(), ); + + // If a test is revisioned, it's fixed source file can be named "a.foo.fixed", which, + // well, "a.foo" isn't a valid crate name. So we explicitly mangle the test name + // (including the revision) here to avoid the test writer having to manually specify a + // `#![crate_name = "..."]` as a workaround. This is okay since we're only checking if + // the fixed code is compilable. + if self.revision.is_some() { + let crate_name = + self.testpaths.file.file_stem().expect("test must have a file stem"); + // crate name must be alphanumeric or `_`. + let crate_name = + crate_name.to_str().expect("crate name implies file name must be valid UTF-8"); + // replace `a.foo` -> `a__foo` for crate name purposes. + // replace `revision-name-with-dashes` -> `revision_name_with_underscore` + let crate_name = crate_name.replace(".", "__"); + let crate_name = crate_name.replace("-", "_"); + rustc.arg("--crate-name"); + rustc.arg(crate_name); + } + let res = self.compose_and_run_compiler(rustc, None); if !res.status.success() { self.fatal_proc_rec("failed to compile fixed code", &res); diff --git a/src/tools/compiletest/src/runtest/tests.rs b/src/tools/compiletest/src/runtest/tests.rs index ee42243e83d..817b56109a5 100644 --- a/src/tools/compiletest/src/runtest/tests.rs +++ b/src/tools/compiletest/src/runtest/tests.rs @@ -50,72 +50,68 @@ fn normalize_platform_differences() { } /// Test for anonymizing line numbers in coverage reports, especially for -/// branch regions. +/// MC/DC regions. /// -/// FIXME(#119681): This test can be removed when we have examples of branch +/// FIXME(#123409): This test can be removed when we have examples of MC/DC /// coverage in the actual coverage test suite. #[test] fn anonymize_coverage_line_numbers() { let anon = |coverage| TestCx::anonymize_coverage_line_numbers(coverage); let input = r#" - 6| 3|fn print_size<T>() { - 7| 3| if std::mem::size_of::<T>() > 4 { + 7| 2|fn mcdc_check_neither(a: bool, b: bool) { + 8| 2| if a && b { + ^0 ------------------ - | Branch (7:8): [True: 0, False: 1] - | Branch (7:8): [True: 0, False: 1] - | Branch (7:8): [True: 1, False: 0] + |---> MC/DC Decision Region (8:8) to (8:14) + | + | Number of Conditions: 2 + | Condition C1 --> (8:8) + | Condition C2 --> (8:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | + | C1-Pair: not covered + | C2-Pair: not covered + | MC/DC Coverage for Decision: 0.00% + | ------------------ - 8| 1| println!("size > 4"); + 9| 0| say("a and b"); + 10| 2| } else { + 11| 2| say("not both"); + 12| 2| } + 13| 2|} "#; let expected = r#" - LL| 3|fn print_size<T>() { - LL| 3| if std::mem::size_of::<T>() > 4 { + LL| 2|fn mcdc_check_neither(a: bool, b: bool) { + LL| 2| if a && b { + ^0 ------------------ - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:8): [True: 0, False: 1] - | Branch (LL:8): [True: 1, False: 0] - ------------------ - LL| 1| println!("size > 4"); -"#; - - assert_eq!(anon(input), expected); - - ////////// - - let input = r#" - 12| 3|} - ------------------ - | branch_generics::print_size::<()>: - | 6| 1|fn print_size<T>() { - | 7| 1| if std::mem::size_of::<T>() > 4 { - | ------------------ - | | Branch (7:8): [True: 0, False: 1] - | ------------------ - | 8| 0| println!("size > 4"); - | 9| 1| } else { - | 10| 1| println!("size <= 4"); - | 11| 1| } - | 12| 1|} - ------------------ -"#; - - let expected = r#" - LL| 3|} - ------------------ - | branch_generics::print_size::<()>: - | LL| 1|fn print_size<T>() { - | LL| 1| if std::mem::size_of::<T>() > 4 { - | ------------------ - | | Branch (LL:8): [True: 0, False: 1] - | ------------------ - | LL| 0| println!("size > 4"); - | LL| 1| } else { - | LL| 1| println!("size <= 4"); - | LL| 1| } - | LL| 1|} + |---> MC/DC Decision Region (LL:8) to (LL:14) + | + | Number of Conditions: 2 + | Condition C1 --> (LL:8) + | Condition C2 --> (LL:13) + | + | Executed MC/DC Test Vectors: + | + | C1, C2 Result + | 1 { F, - = F } + | + | C1-Pair: not covered + | C2-Pair: not covered + | MC/DC Coverage for Decision: 0.00% + | ------------------ + LL| 0| say("a and b"); + LL| 2| } else { + LL| 2| say("not both"); + LL| 2| } + LL| 2|} "#; assert_eq!(anon(input), expected); diff --git a/src/tools/coverage-dump/src/covfun.rs b/src/tools/coverage-dump/src/covfun.rs index 49e3a6ed583..b308c8de14f 100644 --- a/src/tools/coverage-dump/src/covfun.rs +++ b/src/tools/coverage-dump/src/covfun.rs @@ -70,7 +70,8 @@ pub(crate) fn dump_covfun_mappings( } // If the mapping is a branch region, print both of its arms // in resolved form (even if they aren't expressions). - MappingKind::Branch { r#true, r#false } => { + MappingKind::Branch { r#true, r#false } + | MappingKind::MCDCBranch { r#true, r#false, .. } => { println!(" true = {}", expression_resolver.format_term(r#true)); println!(" false = {}", expression_resolver.format_term(r#false)); } @@ -164,6 +165,26 @@ impl<'a> Parser<'a> { let r#false = self.read_simple_term()?; Ok(MappingKind::Branch { r#true, r#false }) } + 5 => { + let bitmap_idx = self.read_uleb128_u32()?; + let conditions_num = self.read_uleb128_u32()?; + Ok(MappingKind::MCDCDecision { bitmap_idx, conditions_num }) + } + 6 => { + let r#true = self.read_simple_term()?; + let r#false = self.read_simple_term()?; + let condition_id = self.read_uleb128_u32()?; + let true_next_id = self.read_uleb128_u32()?; + let false_next_id = self.read_uleb128_u32()?; + Ok(MappingKind::MCDCBranch { + r#true, + r#false, + condition_id, + true_next_id, + false_next_id, + }) + } + _ => Err(anyhow!("unknown mapping kind: {raw_mapping_kind:#x}")), } } @@ -224,7 +245,28 @@ enum MappingKind { // Using raw identifiers here makes the dump output a little bit nicer // (via the derived Debug), at the expense of making this tool's source // code a little bit uglier. - Branch { r#true: CovTerm, r#false: CovTerm }, + Branch { + r#true: CovTerm, + r#false: CovTerm, + }, + MCDCBranch { + r#true: CovTerm, + r#false: CovTerm, + // These attributes are printed in Debug but not used directly. + #[allow(dead_code)] + condition_id: u32, + #[allow(dead_code)] + true_next_id: u32, + #[allow(dead_code)] + false_next_id: u32, + }, + MCDCDecision { + // These attributes are printed in Debug but not used directly. + #[allow(dead_code)] + bitmap_idx: u32, + #[allow(dead_code)] + conditions_num: u32, + }, } struct MappingRegion { diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index 592e97310a4..9e08f7e5f9b 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -262,6 +262,7 @@ impl<'a> Validator<'a> { Type::DynTrait(dyn_trait) => self.check_dyn_trait(dyn_trait), Type::Generic(_) => {} Type::Primitive(_) => {} + Type::Pat { type_, __pat_unstable_do_not_use: _ } => self.check_type(type_), Type::FunctionPointer(fp) => self.check_function_pointer(&**fp), Type::Tuple(tys) => tys.iter().for_each(|ty| self.check_type(ty)), Type::Slice(inner) => self.check_type(&**inner), diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 2c5868d5b37..b0dab9f509d 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -24,8 +24,8 @@ jobs: include: - os: ubuntu-latest host_target: x86_64-unknown-linux-gnu - - os: macos-latest - host_target: x86_64-apple-darwin + - os: macos-14 + host_target: aarch64-apple-darwin - os: windows-latest host_target: i686-pc-windows-msvc runs-on: ${{ matrix.os }} @@ -49,15 +49,16 @@ jobs: with: path: | # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>. - ~/.cargo/bin + # Cache package/registry information ~/.cargo/registry/index ~/.cargo/registry/cache ~/.cargo/git/db - # contains package information of crates installed via `cargo install`. + # Cache installed binaries + ~/.cargo/bin ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-reset20230315 + key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-${{ runner.os }}-reset20240331 - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} @@ -98,15 +99,16 @@ jobs: with: path: | # Taken from <https://doc.rust-lang.org/nightly/cargo/guide/cargo-home.html#caching-the-cargo-home-in-ci>. - ~/.cargo/bin + # Cache package/registry information ~/.cargo/registry/index ~/.cargo/registry/cache ~/.cargo/git/db - # contains package information of crates installed via `cargo install`. + # Cache installed binaries + ~/.cargo/bin ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-reset20230315-${{ hashFiles('**/Cargo.lock') }} - restore-keys: ${{ runner.os }}-cargo-reset20230315 + key: cargo-${{ runner.os }}-reset20240331-${{ hashFiles('**/Cargo.lock') }} + restore-keys: cargo-${{ runner.os }}-reset20240331 - name: Install rustup-toolchain-install-master if: ${{ steps.cache.outputs.cache-hit != 'true' }} @@ -130,6 +132,10 @@ jobs: run: ./miri fmt --check - name: clippy run: ./miri clippy -- -D warnings + - name: clippy (no features) + run: ./miri clippy --no-default-features -- -D warnings + - name: clippy (all features) + run: ./miri clippy --all-features -- -D warnings - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" ./miri cargo doc --document-private-items @@ -189,7 +195,7 @@ jobs: with: fetch-depth: 256 # get a bit more of the history - name: install josh-proxy - run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06 + run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04 - name: setup bot git name and email run: | git config --global user.name 'The Miri Cronjob Bot' diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index 3416fb0d9ba..60bc1d5282d 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -241,18 +241,20 @@ We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit chan rustc and Miri repositories. You can install it as follows: ```sh -cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r22.12.06 +RUSTFLAGS="--cap-lints=warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04 ``` Josh will automatically be started and stopped by `./miri`. ### Importing changes from the rustc repo +*Note: this usually happens automatically, so these steps rarely have to be done by hand.* + We assume we start on an up-to-date master branch in the Miri repo. ```sh # Fetch and merge rustc side of the history. Takes ca 5 min the first time. -# This will also update the 'rustc-version' file. +# This will also update the `rustc-version` file. ./miri rustc-pull # Update local toolchain and apply formatting. ./miri toolchain && ./miri fmt @@ -266,12 +268,6 @@ needed. ### Exporting changes to the rustc repo -Keep in mind that pushing is the most complicated job that josh has to do -- pulling just filters -the rustc history, but pushing needs to construct a new rustc history that would filter to the given -Miri history! To avoid problems, it is a good idea to always pull immediately before you push. If -you are getting strange errors, chances are you are running into [this josh -bug](https://github.com/josh-project/josh/issues/998). In that case, please get in touch on Zulip. - We will use the josh proxy to push to your fork of rustc. Run the following in the Miri repo, assuming we are on an up-to-date master branch: @@ -280,9 +276,9 @@ assuming we are on an up-to-date master branch: ./miri rustc-push YOUR_NAME miri ``` -This will create a new branch called 'miri' in your fork, and the output should -include a link to create a rustc PR that will integrate those changes into the -main repository. +This will create a new branch called `miri` in your fork, and the output should include a link that +creates a rustc PR to integrate those changes into the main repository. If that PR has conflicts, +you need to pull rustc changes into Miri first, and then re-do the rustc push. If this fails due to authentication problems, it can help to make josh push via ssh instead of https. Add the following to your `.gitconfig`: diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index cccf10a7d70..f8ba612750e 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -27,60 +27,59 @@ export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--locked" -# Determine configuration for installed build +# Determine configuration for installed build (used by test-cargo-miri). echo "Installing release version of Miri" -./miri install - -echo "Checking various feature flag configurations" -./miri check --no-default-features # make sure this can be built -./miri check # and this, too -# `--all-features` is used for the build below, so no extra check needed. +time ./miri install # Prepare debug build for direct `./miri` invocations. # We enable all features to make sure the Stacked Borrows consistency check runs. echo "Building debug version of Miri" export CARGO_EXTRA_FLAGS="$CARGO_EXTRA_FLAGS --all-features" -./miri build --all-targets # the build that all the `./miri test` below will use +time ./miri build --all-targets # the build that all the `./miri test` below will use endgroup -# Test +# Run tests. Recognizes these variables: +# - MIRI_TEST_TARGET: the target to test. Empty for host target. +# - GC_STRESS: if non-empty, run the GC stress test for the main test suite. +# - MIR_OPT: if non-empty, re-run test `pass` tests with mir-opt-level=4 +# - MANY_SEEDS: if set to N, run the "many-seeds" tests N times +# - TEST_BENCH: if non-empty, check that the benchmarks all build +# - CARGO_MIRI_ENV: if non-empty, set some env vars and config to potentially confuse cargo-miri function run_tests { - if [ -n "${MIRI_TEST_TARGET:-}" ]; then + if [ -n "${MIRI_TEST_TARGET-}" ]; then begingroup "Testing foreign architecture $MIRI_TEST_TARGET" else begingroup "Testing host architecture" fi ## ui test suite - # On the host, also stress-test the GC. - if [ -z "${MIRI_TEST_TARGET:-}" ]; then - MIRIFLAGS="${MIRIFLAGS:-} -Zmiri-provenance-gc=1" ./miri test + if [ -n "${GC_STRESS-}" ]; then + time MIRIFLAGS="${MIRIFLAGS-} -Zmiri-provenance-gc=1" ./miri test else - ./miri test + time ./miri test fi - # Host-only tests - if [ -z "${MIRI_TEST_TARGET:-}" ]; then - # Running these on all targets is unlikely to catch more problems and would - # cost a lot of CI time. - + ## advanced tests + if [ -n "${MIR_OPT-}" ]; then # Tests with optimizations (`-O` is what cargo passes, but crank MIR optimizations up all the # way, too). # Optimizations change diagnostics (mostly backtraces), so we don't check # them. Also error locations change so we don't run the failing tests. # We explicitly enable debug-assertions here, they are disabled by -O but we have tests # which exist to check that we panic on debug assertion failures. - MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} - + time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} + fi + if [ -n "${MANY_SEEDS-}" ]; then # Also run some many-seeds tests. 64 seeds means this takes around a minute per test. # (Need to invoke via explicit `bash -c` for Windows.) - for FILE in tests/many-seeds/*.rs; do - MIRI_SEEDS=64 ./miri many-seeds "$BASH" -c "./miri run '$FILE'" + time for FILE in tests/many-seeds/*.rs; do + MIRI_SEEDS=$MANY_SEEDS ./miri many-seeds "$BASH" -c "./miri run '$FILE'" done - + fi + if [ -n "${TEST_BENCH-}" ]; then # Check that the benchmarks build and run, but without actually benchmarking. - HYPERFINE="'$BASH' -c" ./miri bench + time HYPERFINE="'$BASH' -c" ./miri bench fi ## test-cargo-miri @@ -91,16 +90,18 @@ function run_tests { PYTHON=python fi # Some environment setup that attempts to confuse the heck out of cargo-miri. - if [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then - # These act up on Windows (`which miri` produces a filename that does not exist?!?), - # so let's do this only on Linux. Also makes sure things work without these set. - export RUSTC=$(which rustc) # Produces a warning unless we also set MIRI + if [ -n "${CARGO_MIRI_ENV-}" ]; then + # These act up on Windows (`which miri` produces a filename that does not exist?!?). + # RUSTC is the main thing to set (it changes the first argument our wrapper will see). + # Unless MIRI is also set, that produces a warning. + export RUSTC=$(which rustc) export MIRI=$(rustc +miri --print sysroot)/bin/miri + # We entirely ignore other wrappers. + mkdir -p .cargo + echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml fi - mkdir -p .cargo - echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml # Run the actual test - ${PYTHON} test-cargo-miri/run-test.py + time ${PYTHON} test-cargo-miri/run-test.py # Clean up unset RUSTC MIRI rm -rf .cargo @@ -109,7 +110,7 @@ function run_tests { } function run_tests_minimal { - if [ -n "${MIRI_TEST_TARGET:-}" ]; then + if [ -n "${MIRI_TEST_TARGET-}" ]; then begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@" else echo "run_tests_minimal requires MIRI_TEST_TARGET to be set" @@ -126,38 +127,49 @@ function run_tests_minimal { ## Main Testing Logic ## -# Host target. -run_tests - -# Extra targets. # In particular, fully cover all tier 1 targets. case $HOST_TARGET in x86_64-unknown-linux-gnu) + # Host + GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + # Extra tier 1 MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=aarch64-apple-darwin run_tests + MIRI_TEST_TARGET=x86_64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests + # Extra tier 2 + MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests - # Some targets are only partially supported. + # Partially supported targets (tier 2) MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus MIRI_TEST_TARGET=i686-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple pthread-threadname libc-getentropy libc-getrandom libc-misc libc-fs atomic env align num_cpus - MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal no_std integer strings wasm MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std integer strings wasm - MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std # no_std embedded architecture - MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std # JSON target file + MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std + # Custom target JSON file + MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std ;; - x86_64-apple-darwin) + aarch64-apple-darwin) + # Host (tier 2) + GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests + # Extra tier 1 + MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests + # Extra tier 2 MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture - MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests ;; i686-pc-windows-msvc) + # Host + # Only smoke-test `many-seeds`; 64 runs take 15min here! + GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=1 TEST_BENCH=1 run_tests + # Extra tier 1 + # We really want to ensure a Linux target works on a Windows host, + # and a 64bit target works on a 32bit host. MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests ;; *) - echo "FATAL: unknown OS" + echo "FATAL: unknown host target: $HOST_TARGET" exit 1 ;; esac diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 58deac66560..55b3b62819f 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -297,7 +297,7 @@ impl Command { }; // Prepare the branch. Pushing works much better if we use as base exactly // the commit that we pulled from last time, so we use the `rust-version` - // file as a good approximation of that. + // file to find out which commit that would be. println!("Preparing {github_user}/rust (base: {base})..."); if cmd!(sh, "git fetch https://github.com/{github_user}/rust {branch}") .ignore_stderr() diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 187756851c7..6ad8fba723c 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -5baf1e13f568b61e121953bf6a3d09faee7dd446 +23d47dba319331d4418827cfbb8c1af283497d3c diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs index 2690bc026a1..b9f0b5bc17a 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs @@ -48,7 +48,7 @@ impl AccessCause { /// Complete data for an event: #[derive(Clone, Debug)] pub struct Event { - /// Transformation of permissions that occured because of this event. + /// Transformation of permissions that occurred because of this event. pub transition: PermTransition, /// Kind of the access that triggered this event. pub access_cause: AccessCause, @@ -58,7 +58,7 @@ pub struct Event { /// `None` means that this is an implicit access to the entire allocation /// (used for the implicit read on protector release). pub access_range: Option<AllocRange>, - /// The transition recorded by this event only occured on a subrange of + /// The transition recorded by this event only occurred on a subrange of /// `access_range`: a single access on `access_range` triggers several events, /// each with their own mutually disjoint `transition_range`. No-op transitions /// should not be recorded as events, so the union of all `transition_range` is not diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 0fea78daa88..2470624181e 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -473,7 +473,7 @@ impl Tree { let rperms = { let mut perms = UniValMap::default(); // We manually set it to `Active` on all in-bounds positions. - // We also ensure that it is initalized, so that no `Active` but + // We also ensure that it is initialized, so that no `Active` but // not yet initialized nodes exist. Essentially, we pretend there // was a write that initialized these to `Active`. perms.insert(root_idx, LocationState::new_init(Permission::new_active())); diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs index f568850d8db..6777f41ac2d 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs @@ -75,7 +75,7 @@ fn protected_enforces_noalias() { } } -/// We are going to exhaustively test the possibily of inserting +/// We are going to exhaustively test the possibility of inserting /// a spurious read in some code. /// /// We choose some pointer `x` through which we want a spurious read to be inserted. @@ -270,7 +270,7 @@ mod spurious_read { match self { TestEvent::Access(acc) => write!(f, "{acc}"), // The fields of the `Ret` variants just serve to make them - // impossible to instanciate via the `RetX = NoRet` type; we can + // impossible to instantiate via the `RetX = NoRet` type; we can // always ignore their value. TestEvent::RetX(_) => write!(f, "ret x"), TestEvent::RetY(_) => write!(f, "ret y"), @@ -395,7 +395,7 @@ mod spurious_read { match evt { TestEvent::Access(acc) => self.perform_test_access(acc), // The fields of the `Ret` variants just serve to make them - // impossible to instanciate via the `RetX = NoRet` type; we can + // impossible to instantiate via the `RetX = NoRet` type; we can // always ignore their value. TestEvent::RetX(_) => self.end_protector_x(), TestEvent::RetY(_) => self.end_protector_y(), diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 2137de6a29b..ff081328a72 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -31,7 +31,7 @@ use rustc_target::spec::abi::Abi; use crate::{ concurrency::{data_race, weak_memory}, - shims::unix::FileHandler, + shims::unix::FdTable, *, }; @@ -463,9 +463,9 @@ pub struct MiriMachine<'mir, 'tcx> { pub(crate) validate: bool, /// The table of file descriptors. - pub(crate) file_handler: shims::unix::FileHandler, + pub(crate) fds: shims::unix::FdTable, /// The table of directory descriptors. - pub(crate) dir_handler: shims::unix::DirHandler, + pub(crate) dirs: shims::unix::DirTable, /// This machine's monotone clock. pub(crate) clock: Clock, @@ -640,8 +640,8 @@ impl<'mir, 'tcx> MiriMachine<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, - file_handler: FileHandler::new(config.mute_stdout_stderr), - dir_handler: Default::default(), + fds: FdTable::new(config.mute_stdout_stderr), + dirs: Default::default(), layouts, threads: ThreadManager::default(), static_roots: Vec::new(), @@ -774,11 +774,11 @@ impl VisitProvenance for MiriMachine<'_, '_> { argv, cmd_line, extern_statics, - dir_handler, + dirs, borrow_tracker, data_race, alloc_addresses, - file_handler, + fds, tcx: _, isolated_op: _, validate: _, @@ -817,8 +817,8 @@ impl VisitProvenance for MiriMachine<'_, '_> { threads.visit_provenance(visit); tls.visit_provenance(visit); env_vars.visit_provenance(visit); - dir_handler.visit_provenance(visit); - file_handler.visit_provenance(visit); + dirs.visit_provenance(visit); + fds.visit_provenance(visit); data_race.visit_provenance(visit); borrow_tracker.visit_provenance(visit); alloc_addresses.visit_provenance(visit); @@ -1066,7 +1066,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { let extern_decl_layout = ecx.tcx.layout_of(ty::ParamEnv::empty().and(def_ty)).unwrap(); if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align { throw_unsup_format!( - "`extern` static `{name}` from crate `{krate}` has been declared \ + "extern static `{link_name}` has been declared as `{krate}::{name}` \ with a size of {decl_size} bytes and alignment of {decl_align} bytes, \ but Miri emulates it via an extern static shim \ with a size of {shim_size} bytes and alignment of {shim_align} bytes", @@ -1080,11 +1080,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> { } Ok(ptr) } else { - throw_unsup_format!( - "`extern` static `{name}` from crate `{krate}` is not supported by Miri", - name = ecx.tcx.def_path_str(def_id), - krate = ecx.tcx.crate_name(def_id.krate), - ) + throw_unsup_format!("extern static `{link_name}` is not supported by Miri",) } } diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs new file mode 100644 index 00000000000..a5fe38b902d --- /dev/null +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -0,0 +1,431 @@ +//! General management of file descriptors, and support for +//! standard file descriptors (stdin/stdout/stderr). + +use std::any::Any; +use std::collections::BTreeMap; +use std::io::{self, ErrorKind, IsTerminal, Read, SeekFrom, Write}; + +use rustc_middle::ty::TyCtxt; +use rustc_target::abi::Size; + +use crate::shims::unix::*; +use crate::*; + +/// Represents an open file descriptor. +pub trait FileDescriptor: std::fmt::Debug + Any { + fn name(&self) -> &'static str; + + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + _tcx: TyCtxt<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + throw_unsup_format!("cannot read from {}", self.name()); + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + _bytes: &[u8], + _tcx: TyCtxt<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + throw_unsup_format!("cannot write to {}", self.name()); + } + + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result<u64>> { + throw_unsup_format!("cannot seek on {}", self.name()); + } + + fn close<'tcx>( + self: Box<Self>, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result<i32>> { + throw_unsup_format!("cannot close {}", self.name()); + } + + /// Return a new file descriptor *that refers to the same underlying object*. + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>; + + fn is_tty(&self, _communicate_allowed: bool) -> bool { + // Most FDs are not tty's and the consequence of a wrong `false` are minor, + // so we use a default impl here. + false + } +} + +impl dyn FileDescriptor { + #[inline(always)] + pub fn downcast_ref<T: Any>(&self) -> Option<&T> { + (self as &dyn Any).downcast_ref() + } + + #[inline(always)] + pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { + (self as &mut dyn Any).downcast_mut() + } +} + +impl FileDescriptor for io::Stdin { + fn name(&self) -> &'static str { + "stdin" + } + + fn read<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + _tcx: TyCtxt<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + if !communicate_allowed { + // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. + helpers::isolation_abort_error("`read` from stdin")?; + } + Ok(Read::read(self, bytes)) + } + + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { + Ok(Box::new(io::stdin())) + } + + fn is_tty(&self, communicate_allowed: bool) -> bool { + communicate_allowed && self.is_terminal() + } +} + +impl FileDescriptor for io::Stdout { + fn name(&self) -> &'static str { + "stdout" + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + _tcx: TyCtxt<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + // We allow writing to stderr even with isolation enabled. + let result = Write::write(&mut { self }, bytes); + // Stdout is buffered, flush to make sure it appears on the + // screen. This is the write() syscall of the interpreted + // program, we want it to correspond to a write() syscall on + // the host -- there is no good in adding extra buffering + // here. + io::stdout().flush().unwrap(); + + Ok(result) + } + + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { + Ok(Box::new(io::stdout())) + } + + fn is_tty(&self, communicate_allowed: bool) -> bool { + communicate_allowed && self.is_terminal() + } +} + +impl FileDescriptor for io::Stderr { + fn name(&self) -> &'static str { + "stderr" + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + _tcx: TyCtxt<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + // We allow writing to stderr even with isolation enabled. + // No need to flush, stderr is not buffered. + Ok(Write::write(&mut { self }, bytes)) + } + + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { + Ok(Box::new(io::stderr())) + } + + fn is_tty(&self, communicate_allowed: bool) -> bool { + communicate_allowed && self.is_terminal() + } +} + +/// Like /dev/null +#[derive(Debug)] +pub struct NullOutput; + +impl FileDescriptor for NullOutput { + fn name(&self) -> &'static str { + "stderr and stdout" + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + _tcx: TyCtxt<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + // We just don't write anything, but report to the user that we did. + Ok(Ok(bytes.len())) + } + + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { + Ok(Box::new(NullOutput)) + } +} + +/// The file descriptor table +#[derive(Debug)] +pub struct FdTable { + pub fds: BTreeMap<i32, Box<dyn FileDescriptor>>, +} + +impl VisitProvenance for FdTable { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // All our FileDescriptor do not have any tags. + } +} + +impl FdTable { + pub(crate) fn new(mute_stdout_stderr: bool) -> FdTable { + let mut fds: BTreeMap<_, Box<dyn FileDescriptor>> = BTreeMap::new(); + fds.insert(0i32, Box::new(io::stdin())); + if mute_stdout_stderr { + fds.insert(1i32, Box::new(NullOutput)); + fds.insert(2i32, Box::new(NullOutput)); + } else { + fds.insert(1i32, Box::new(io::stdout())); + fds.insert(2i32, Box::new(io::stderr())); + } + FdTable { fds } + } + + pub fn insert_fd(&mut self, file_handle: Box<dyn FileDescriptor>) -> i32 { + self.insert_fd_with_min_fd(file_handle, 0) + } + + /// Insert a new FD that is at least `min_fd`. + pub fn insert_fd_with_min_fd( + &mut self, + file_handle: Box<dyn FileDescriptor>, + min_fd: i32, + ) -> i32 { + // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in + // between used FDs, the find_map combinator will return it. If the first such unused FD + // is after all other used FDs, the find_map combinator will return None, and we will use + // the FD following the greatest FD thus far. + let candidate_new_fd = + self.fds.range(min_fd..).zip(min_fd..).find_map(|((fd, _fh), counter)| { + if *fd != counter { + // There was a gap in the fds stored, return the first unused one + // (note that this relies on BTreeMap iterating in key order) + Some(counter) + } else { + // This fd is used, keep going + None + } + }); + let new_fd = candidate_new_fd.unwrap_or_else(|| { + // find_map ran out of BTreeMap entries before finding a free fd, use one plus the + // maximum fd in the map + self.fds.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) + }); + + self.fds.try_insert(new_fd, file_handle).unwrap(); + new_fd + } + + pub fn get(&self, fd: i32) -> Option<&dyn FileDescriptor> { + Some(&**self.fds.get(&fd)?) + } + + pub fn get_mut(&mut self, fd: i32) -> Option<&mut dyn FileDescriptor> { + Some(&mut **self.fds.get_mut(&fd)?) + } + + pub fn remove(&mut self, fd: i32) -> Option<Box<dyn FileDescriptor>> { + self.fds.remove(&fd) + } + + pub fn is_fd(&self, fd: i32) -> bool { + self.fds.contains_key(&fd) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if args.len() < 2 { + throw_ub_format!( + "incorrect number of arguments for fcntl: got {}, expected at least 2", + args.len() + ); + } + let fd = this.read_scalar(&args[0])?.to_i32()?; + let cmd = this.read_scalar(&args[1])?.to_i32()?; + + // We only support getting the flags for a descriptor. + if cmd == this.eval_libc_i32("F_GETFD") { + // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the + // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` + // always sets this flag when opening a file. However we still need to check that the + // file itself is open. + if this.machine.fds.is_fd(fd) { + Ok(this.eval_libc_i32("FD_CLOEXEC")) + } else { + this.fd_not_found() + } + } else if cmd == this.eval_libc_i32("F_DUPFD") + || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC") + { + // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part + // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only + // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, + // thus they can share the same implementation here. + if args.len() < 3 { + throw_ub_format!( + "incorrect number of arguments for fcntl with cmd=`F_DUPFD`/`F_DUPFD_CLOEXEC`: got {}, expected at least 3", + args.len() + ); + } + let start = this.read_scalar(&args[2])?.to_i32()?; + + match this.machine.fds.get_mut(fd) { + Some(file_descriptor) => { + let dup_result = file_descriptor.dup(); + match dup_result { + Ok(dup_fd) => Ok(this.machine.fds.insert_fd_with_min_fd(dup_fd, start)), + Err(e) => { + this.set_last_error_from_io_error(e.kind())?; + Ok(-1) + } + } + } + None => this.fd_not_found(), + } + } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fcntl`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + + this.ffullsync_fd(fd) + } else { + throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd); + } + } + + fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar<Provenance>> { + let this = self.eval_context_mut(); + + let fd = this.read_scalar(fd_op)?.to_i32()?; + + Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.remove(fd) { + let result = file_descriptor.close(this.machine.communicate())?; + this.try_unwrap_io_result(result)? + } else { + this.fd_not_found()? + })) + } + + /// Function used when a file descriptor does not exist. It returns `Ok(-1)`and sets + /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses + /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer + /// types (like `read`, that returns an `i64`). + fn fd_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> { + let this = self.eval_context_mut(); + let ebadf = this.eval_libc("EBADF"); + this.set_last_error(ebadf)?; + Ok((-1).into()) + } + + fn read( + &mut self, + fd: i32, + buf: Pointer<Option<Provenance>>, + count: u64, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + // Isolation check is done via `FileDescriptor` trait. + + trace!("Reading from FD {}, size {}", fd, count); + + // Check that the *entire* buffer is actually valid memory. + this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; + + // We cap the number of read bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. This saves us from having to handle overflows later. + let count = count + .min(u64::try_from(this.target_isize_max()).unwrap()) + .min(u64::try_from(isize::MAX).unwrap()); + let communicate = this.machine.communicate(); + + if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { + trace!("read: FD mapped to {:?}", file_descriptor); + // We want to read at most `count` bytes. We are sure that `count` is not negative + // because it was a target's `usize`. Also we are sure that its smaller than + // `usize::MAX` because it is bounded by the host's `isize`. + let mut bytes = vec![0; usize::try_from(count).unwrap()]; + // `File::read` never returns a value larger than `count`, + // so this cannot fail. + let result = file_descriptor + .read(communicate, &mut bytes, *this.tcx)? + .map(|c| i64::try_from(c).unwrap()); + + match result { + Ok(read_bytes) => { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.write_bytes_ptr(buf, bytes)?; + Ok(read_bytes) + } + Err(e) => { + this.set_last_error_from_io_error(e.kind())?; + Ok(-1) + } + } + } else { + trace!("read: FD not found"); + this.fd_not_found() + } + } + + fn write( + &mut self, + fd: i32, + buf: Pointer<Option<Provenance>>, + count: u64, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + // Isolation check is done via `FileDescriptor` trait. + + // Check that the *entire* buffer is actually valid memory. + this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; + + // We cap the number of written bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. This saves us from having to handle overflows later. + let count = count + .min(u64::try_from(this.target_isize_max()).unwrap()) + .min(u64::try_from(isize::MAX).unwrap()); + let communicate = this.machine.communicate(); + + if let Some(file_descriptor) = this.machine.fds.get(fd) { + let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?; + let result = file_descriptor + .write(communicate, bytes, *this.tcx)? + .map(|c| i64::try_from(c).unwrap()); + this.try_unwrap_io_result(result) + } else { + this.fd_not_found() + } + } +} diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index 4ceda809350..3a56aa9138b 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -6,12 +6,9 @@ use rustc_span::Symbol; use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi; +use crate::shims::unix::*; use crate::*; use shims::foreign_items::EmulateForeignItemResult; -use shims::unix::fs::EvalContextExt as _; -use shims::unix::mem::EvalContextExt as _; -use shims::unix::sync::EvalContextExt as _; -use shims::unix::thread::EvalContextExt as _; use shims::unix::freebsd::foreign_items as freebsd; use shims::unix::linux::foreign_items as linux; @@ -51,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. #[rustfmt::skip] match link_name.as_str() { - // Environment related shims + // Environment variables "getenv" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; @@ -79,25 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_i32(result), dest)?; } - // File related shims - "open" | "open64" => { - // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; - let result = this.open(args)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - "close" => { - let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.close(fd)?; - this.write_scalar(result, dest)?; - } - "fcntl" => { - // `fcntl` is variadic. The argument count is checked based on the first argument - // in `this.fcntl()`, so we do not use `check_shim` here. - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; - let result = this.fcntl(args)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } + // File descriptors "read" => { let [fd, buf, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; @@ -116,6 +95,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_target_isize(result, this), dest)?; } + "close" => { + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.close(fd)?; + this.write_scalar(result, dest)?; + } + "fcntl" => { + // `fcntl` is variadic. The argument count is checked based on the first argument + // in `this.fcntl()`, so we do not use `check_shim` here. + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + let result = this.fcntl(args)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + + // File and file system access + "open" | "open64" => { + // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + let result = this.open(args)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } "unlink" => { let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unlink(path)?; @@ -219,7 +218,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(Scalar::from_i32(result), dest)?; } - // Time related shims + // Sockets + "socketpair" => { + let [domain, type_, protocol, sv] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + let result = this.socketpair(domain, type_, protocol, sv)?; + this.write_scalar(result, dest)?; + } + + // Time "gettimeofday" => { let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.gettimeofday(tv, tz)?; @@ -598,7 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if bufsize > 256 { let err = this.eval_libc("EIO"); this.set_last_error(err)?; - this.write_scalar(Scalar::from_i32(-1), dest)? + this.write_scalar(Scalar::from_i32(-1), dest)?; } else { this.gen_random(buf, bufsize)?; this.write_scalar(Scalar::from_i32(0), dest)?; diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs index 6814e0d4283..ffb583123d4 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -1,10 +1,9 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; +use crate::shims::unix::*; use crate::*; use shims::foreign_items::EmulateForeignItemResult; -use shims::unix::fs::EvalContextExt as _; -use shims::unix::thread::EvalContextExt as _; pub fn is_dyn_sym(_name: &str) -> bool { false diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index b141ca4a019..31076fdfaf6 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -1,6 +1,6 @@ -use std::any::Any; +//! File and file system access + use std::borrow::Cow; -use std::collections::BTreeMap; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; @@ -13,70 +13,16 @@ use rustc_middle::ty::TyCtxt; use rustc_target::abi::Size; use crate::shims::os_str::bytes_to_os_str; +use crate::shims::unix::*; use crate::*; use shims::time::system_time_to_duration; #[derive(Debug)] -pub struct FileHandle { +struct FileHandle { file: File, writable: bool, } -pub trait FileDescriptor: std::fmt::Debug + Any { - fn name(&self) -> &'static str; - - fn read<'tcx>( - &mut self, - _communicate_allowed: bool, - _bytes: &mut [u8], - _tcx: TyCtxt<'tcx>, - ) -> InterpResult<'tcx, io::Result<usize>> { - throw_unsup_format!("cannot read from {}", self.name()); - } - - fn write<'tcx>( - &self, - _communicate_allowed: bool, - _bytes: &[u8], - _tcx: TyCtxt<'tcx>, - ) -> InterpResult<'tcx, io::Result<usize>> { - throw_unsup_format!("cannot write to {}", self.name()); - } - - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result<u64>> { - throw_unsup_format!("cannot seek on {}", self.name()); - } - - fn close<'tcx>( - self: Box<Self>, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result<i32>> { - throw_unsup_format!("cannot close {}", self.name()); - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>>; - - fn is_tty(&self, _communicate_allowed: bool) -> bool { - false - } -} - -impl dyn FileDescriptor { - #[inline(always)] - pub fn downcast_ref<T: Any>(&self) -> Option<&T> { - (self as &dyn Any).downcast_ref() - } - - #[inline(always)] - pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> { - (self as &mut dyn Any).downcast_mut() - } -} - impl FileDescriptor for FileHandle { fn name(&self) -> &'static str { "FILE" @@ -147,172 +93,6 @@ impl FileDescriptor for FileHandle { } } -impl FileDescriptor for io::Stdin { - fn name(&self) -> &'static str { - "stdin" - } - - fn read<'tcx>( - &mut self, - communicate_allowed: bool, - bytes: &mut [u8], - _tcx: TyCtxt<'tcx>, - ) -> InterpResult<'tcx, io::Result<usize>> { - if !communicate_allowed { - // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. - helpers::isolation_abort_error("`read` from stdin")?; - } - Ok(Read::read(self, bytes)) - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(io::stdin())) - } - - fn is_tty(&self, communicate_allowed: bool) -> bool { - communicate_allowed && self.is_terminal() - } -} - -impl FileDescriptor for io::Stdout { - fn name(&self) -> &'static str { - "stdout" - } - - fn write<'tcx>( - &self, - _communicate_allowed: bool, - bytes: &[u8], - _tcx: TyCtxt<'tcx>, - ) -> InterpResult<'tcx, io::Result<usize>> { - // We allow writing to stderr even with isolation enabled. - let result = Write::write(&mut { self }, bytes); - // Stdout is buffered, flush to make sure it appears on the - // screen. This is the write() syscall of the interpreted - // program, we want it to correspond to a write() syscall on - // the host -- there is no good in adding extra buffering - // here. - io::stdout().flush().unwrap(); - - Ok(result) - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(io::stdout())) - } - - fn is_tty(&self, communicate_allowed: bool) -> bool { - communicate_allowed && self.is_terminal() - } -} - -impl FileDescriptor for io::Stderr { - fn name(&self) -> &'static str { - "stderr" - } - - fn write<'tcx>( - &self, - _communicate_allowed: bool, - bytes: &[u8], - _tcx: TyCtxt<'tcx>, - ) -> InterpResult<'tcx, io::Result<usize>> { - // We allow writing to stderr even with isolation enabled. - // No need to flush, stderr is not buffered. - Ok(Write::write(&mut { self }, bytes)) - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(io::stderr())) - } - - fn is_tty(&self, communicate_allowed: bool) -> bool { - communicate_allowed && self.is_terminal() - } -} - -#[derive(Debug)] -struct NullOutput; - -impl FileDescriptor for NullOutput { - fn name(&self) -> &'static str { - "stderr and stdout" - } - - fn write<'tcx>( - &self, - _communicate_allowed: bool, - bytes: &[u8], - _tcx: TyCtxt<'tcx>, - ) -> InterpResult<'tcx, io::Result<usize>> { - // We just don't write anything, but report to the user that we did. - Ok(Ok(bytes.len())) - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(NullOutput)) - } -} - -#[derive(Debug)] -pub struct FileHandler { - pub handles: BTreeMap<i32, Box<dyn FileDescriptor>>, -} - -impl VisitProvenance for FileHandler { - fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { - // All our FileDescriptor do not have any tags. - } -} - -impl FileHandler { - pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { - let mut handles: BTreeMap<_, Box<dyn FileDescriptor>> = BTreeMap::new(); - handles.insert(0i32, Box::new(io::stdin())); - if mute_stdout_stderr { - handles.insert(1i32, Box::new(NullOutput)); - handles.insert(2i32, Box::new(NullOutput)); - } else { - handles.insert(1i32, Box::new(io::stdout())); - handles.insert(2i32, Box::new(io::stderr())); - } - FileHandler { handles } - } - - pub fn insert_fd(&mut self, file_handle: Box<dyn FileDescriptor>) -> i32 { - self.insert_fd_with_min_fd(file_handle, 0) - } - - fn insert_fd_with_min_fd(&mut self, file_handle: Box<dyn FileDescriptor>, min_fd: i32) -> i32 { - // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in - // between used FDs, the find_map combinator will return it. If the first such unused FD - // is after all other used FDs, the find_map combinator will return None, and we will use - // the FD following the greatest FD thus far. - let candidate_new_fd = - self.handles.range(min_fd..).zip(min_fd..).find_map(|((fd, _fh), counter)| { - if *fd != counter { - // There was a gap in the fds stored, return the first unused one - // (note that this relies on BTreeMap iterating in key order) - Some(counter) - } else { - // This fd is used, keep going - None - } - }); - let new_fd = candidate_new_fd.unwrap_or_else(|| { - // find_map ran out of BTreeMap entries before finding a free fd, use one plus the - // maximum fd in the map - self.handles - .last_key_value() - .map(|(fd, _)| fd.checked_add(1).unwrap()) - .unwrap_or(min_fd) - }); - - self.handles.try_insert(new_fd, file_handle).unwrap(); - new_fd - } -} - impl<'mir, 'tcx: 'mir> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { fn macos_stat_write_buf( @@ -411,10 +191,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx /// An open directory, tracked by DirHandler. #[derive(Debug)] -pub struct OpenDir { +struct OpenDir { /// The directory reader on the host. read_dir: ReadDir, - /// The most recent entry returned by readdir() + /// The most recent entry returned by readdir(). + /// Will be freed by the next call. entry: Pointer<Option<Provenance>>, } @@ -425,8 +206,11 @@ impl OpenDir { } } +/// The table of open directories. +/// Curiously, Unix/POSIX does not unify this into the "file descriptor" concept... everything +/// is a file, except a directory is not? #[derive(Debug)] -pub struct DirHandler { +pub struct DirTable { /// Directory iterators used to emulate libc "directory streams", as used in opendir, readdir, /// and closedir. /// @@ -441,7 +225,7 @@ pub struct DirHandler { next_id: u64, } -impl DirHandler { +impl DirTable { #[allow(clippy::arithmetic_side_effects)] fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; @@ -451,9 +235,9 @@ impl DirHandler { } } -impl Default for DirHandler { - fn default() -> DirHandler { - DirHandler { +impl Default for DirTable { + fn default() -> DirTable { + DirTable { streams: FxHashMap::default(), // Skip 0 as an ID, because it looks like a null pointer to libc next_id: 1, @@ -461,9 +245,9 @@ impl Default for DirHandler { } } -impl VisitProvenance for DirHandler { +impl VisitProvenance for DirTable { fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - let DirHandler { streams, next_id: _ } = self; + let DirTable { streams, next_id: _ } = self; for dir in streams.values() { dir.entry.visit_provenance(visit); @@ -615,200 +399,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } let fd = options.open(path).map(|file| { - let fh = &mut this.machine.file_handler; + let fh = &mut this.machine.fds; fh.insert_fd(Box::new(FileHandle { file, writable })) }); this.try_unwrap_io_result(fd) } - fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - if args.len() < 2 { - throw_ub_format!( - "incorrect number of arguments for fcntl: got {}, expected at least 2", - args.len() - ); - } - let fd = this.read_scalar(&args[0])?.to_i32()?; - let cmd = this.read_scalar(&args[1])?.to_i32()?; - - // We only support getting the flags for a descriptor. - if cmd == this.eval_libc_i32("F_GETFD") { - // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the - // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` - // always sets this flag when opening a file. However we still need to check that the - // file itself is open. - if this.machine.file_handler.handles.contains_key(&fd) { - Ok(this.eval_libc_i32("FD_CLOEXEC")) - } else { - this.handle_not_found() - } - } else if cmd == this.eval_libc_i32("F_DUPFD") - || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC") - { - // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part - // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only - // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, - // thus they can share the same implementation here. - if args.len() < 3 { - throw_ub_format!( - "incorrect number of arguments for fcntl with cmd=`F_DUPFD`/`F_DUPFD_CLOEXEC`: got {}, expected at least 3", - args.len() - ); - } - let start = this.read_scalar(&args[2])?.to_i32()?; - - let fh = &mut this.machine.file_handler; - - match fh.handles.get_mut(&fd) { - Some(file_descriptor) => { - let dup_result = file_descriptor.dup(); - match dup_result { - Ok(dup_fd) => Ok(fh.insert_fd_with_min_fd(dup_fd, start)), - Err(e) => { - this.set_last_error_from_io_error(e.kind())?; - Ok(-1) - } - } - } - None => this.handle_not_found(), - } - } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC") { - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`fcntl`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - - if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - // FIXME: Support fullfsync for all FDs - let FileHandle { file, writable } = - file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { - err_unsup_format!( - "`F_FULLFSYNC` is only supported on file-backed file descriptors" - ) - })?; - let io_result = maybe_sync_file(file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) - } else { - this.handle_not_found() - } - } else { - throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd); - } - } - - fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar<Provenance>> { - let this = self.eval_context_mut(); - - let fd = this.read_scalar(fd_op)?.to_i32()?; - - Ok(Scalar::from_i32( - if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - let result = file_descriptor.close(this.machine.communicate())?; - this.try_unwrap_io_result(result)? - } else { - this.handle_not_found()? - }, - )) - } - - /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets - /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses - /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer - /// types (like `read`, that returns an `i64`). - fn handle_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> { - let this = self.eval_context_mut(); - let ebadf = this.eval_libc("EBADF"); - this.set_last_error(ebadf)?; - Ok((-1).into()) - } - - fn read( - &mut self, - fd: i32, - buf: Pointer<Option<Provenance>>, - count: u64, - ) -> InterpResult<'tcx, i64> { - let this = self.eval_context_mut(); - - // Isolation check is done via `FileDescriptor` trait. - - trace!("Reading from FD {}, size {}", fd, count); - - // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; - - // We cap the number of read bytes to the largest value that we are able to fit in both the - // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count - .min(u64::try_from(this.target_isize_max()).unwrap()) - .min(u64::try_from(isize::MAX).unwrap()); - let communicate = this.machine.communicate(); - - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - trace!("read: FD mapped to {:?}", file_descriptor); - // We want to read at most `count` bytes. We are sure that `count` is not negative - // because it was a target's `usize`. Also we are sure that its smaller than - // `usize::MAX` because it is bounded by the host's `isize`. - let mut bytes = vec![0; usize::try_from(count).unwrap()]; - // `File::read` never returns a value larger than `count`, - // so this cannot fail. - let result = file_descriptor - .read(communicate, &mut bytes, *this.tcx)? - .map(|c| i64::try_from(c).unwrap()); - - match result { - Ok(read_bytes) => { - // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.write_bytes_ptr(buf, bytes)?; - Ok(read_bytes) - } - Err(e) => { - this.set_last_error_from_io_error(e.kind())?; - Ok(-1) - } - } - } else { - trace!("read: FD not found"); - this.handle_not_found() - } - } - - fn write( - &mut self, - fd: i32, - buf: Pointer<Option<Provenance>>, - count: u64, - ) -> InterpResult<'tcx, i64> { - let this = self.eval_context_mut(); - - // Isolation check is done via `FileDescriptor` trait. - - // Check that the *entire* buffer is actually valid memory. - this.check_ptr_access(buf, Size::from_bytes(count), CheckInAllocMsg::MemoryAccessTest)?; - - // We cap the number of written bytes to the largest value that we are able to fit in both the - // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count - .min(u64::try_from(this.target_isize_max()).unwrap()) - .min(u64::try_from(isize::MAX).unwrap()); - let communicate = this.machine.communicate(); - - if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?; - let result = file_descriptor - .write(communicate, bytes, *this.tcx)? - .map(|c| i64::try_from(c).unwrap()); - this.try_unwrap_io_result(result) - } else { - this.handle_not_found() - } - } - fn lseek64( &mut self, fd: i32, @@ -832,16 +429,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { }; let communicate = this.machine.communicate(); - Ok(Scalar::from_i64( - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file_descriptor - .seek(communicate, seek_from)? - .map(|offset| i64::try_from(offset).unwrap()); - this.try_unwrap_io_result(result)? - } else { - this.handle_not_found()? - }, - )) + Ok(Scalar::from_i64(if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { + let result = file_descriptor + .seek(communicate, seek_from)? + .map(|offset| i64::try_from(offset).unwrap()); + this.try_unwrap_io_result(result)? + } else { + this.fd_not_found()? + })) } fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -970,7 +565,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.handle_not_found()?)); + return Ok(Scalar::from_i32(this.fd_not_found()?)); } let metadata = match FileMetadata::from_fd(this, fd)? { @@ -1269,7 +864,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { match result { Ok(dir_iter) => { - let id = this.machine.dir_handler.insert_new(dir_iter); + let id = this.machine.dirs.insert_new(dir_iter); // The libc API for opendir says that this method returns a pointer to an opaque // structure, but we are returning an ID number. Thus, pass it as a scalar of @@ -1301,7 +896,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { return Ok(Scalar::null_ptr(this)); } - let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir64 did not come from opendir") })?; @@ -1366,7 +961,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } }; - let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).unwrap(); + let open_dir = this.machine.dirs.streams.get_mut(&dirp).unwrap(); let old_entry = std::mem::replace(&mut open_dir.entry, entry); this.free(old_entry, MiriMemoryKind::Runtime)?; @@ -1391,10 +986,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.handle_not_found()?)); + return Ok(Scalar::from_i32(this.fd_not_found()?)); } - let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + let open_dir = this.machine.dirs.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; Ok(Scalar::from_i32(match open_dir.read_dir.next() { @@ -1507,15 +1102,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`closedir`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return this.fd_not_found(); } - if let Some(open_dir) = this.machine.dir_handler.streams.remove(&dirp) { + if let Some(open_dir) = this.machine.dirs.streams.remove(&dirp) { this.free(open_dir.entry, MiriMemoryKind::Runtime)?; drop(open_dir); Ok(0) } else { - this.handle_not_found() + this.fd_not_found() } } @@ -1526,37 +1121,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.handle_not_found()?)); + return Ok(Scalar::from_i32(this.fd_not_found()?)); } - Ok(Scalar::from_i32( - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = - file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { - err_unsup_format!( - "`ftruncate64` is only supported on file-backed file descriptors" - ) - })?; - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32))? - } else { - let einval = this.eval_libc("EINVAL"); - this.set_last_error(einval)?; - -1 - } + Ok(Scalar::from_i32(if let Some(file_descriptor) = this.machine.fds.get_mut(fd) { + // FIXME: Support ftruncate64 for all FDs + let FileHandle { file, writable } = + file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`ftruncate64` is only supported on file-backed file descriptors" + ) + })?; + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32))? } else { - // The file is not writable let einval = this.eval_libc("EINVAL"); this.set_last_error(einval)?; -1 } } else { - this.handle_not_found()? - }, - )) + // The file is not writable + let einval = this.eval_libc("EINVAL"); + this.set_last_error(einval)?; + -1 + } + } else { + this.fd_not_found()? + })) } fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1573,20 +1166,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fsync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return this.fd_not_found(); } - if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - // FIXME: Support fsync for all FDs - let FileHandle { file, writable } = - file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { - err_unsup_format!("`fsync` is only supported on file-backed file descriptors") - })?; - let io_result = maybe_sync_file(file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) - } else { - this.handle_not_found() - } + return self.ffullsync_fd(fd); + } + + fn ffullsync_fd(&mut self, fd: i32) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + let Some(file_descriptor) = this.machine.fds.get(fd) else { + return Ok(this.fd_not_found()?); + }; + // Only regular files support synchronization. + let FileHandle { file, writable } = + file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!("`fsync` is only supported on file-backed file descriptors") + })?; + let io_result = maybe_sync_file(file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1598,22 +1195,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fdatasync`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return this.fd_not_found(); } - if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - // FIXME: Support fdatasync for all FDs - let FileHandle { file, writable } = - file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { - err_unsup_format!( - "`fdatasync` is only supported on file-backed file descriptors" - ) - })?; - let io_result = maybe_sync_file(file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) - } else { - this.handle_not_found() - } + let Some(file_descriptor) = this.machine.fds.get(fd) else { + return Ok(this.fd_not_found()?); + }; + // Only regular files support synchronization. + let FileHandle { file, writable } = + file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors") + })?; + let io_result = maybe_sync_file(file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } fn sync_file_range( @@ -1648,22 +1242,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`sync_file_range`", reject_with)?; // Set error code as "EBADF" (bad fd) - return Ok(Scalar::from_i32(this.handle_not_found()?)); + return Ok(Scalar::from_i32(this.fd_not_found()?)); } - if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - // FIXME: Support sync_data_range for all FDs - let FileHandle { file, writable } = - file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { - err_unsup_format!( - "`sync_data_range` is only supported on file-backed file descriptors" - ) - })?; - let io_result = maybe_sync_file(file, *writable, File::sync_data); - Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) - } else { - Ok(Scalar::from_i32(this.handle_not_found()?)) - } + let Some(file_descriptor) = this.machine.fds.get(fd) else { + return Ok(Scalar::from_i32(this.fd_not_found()?)); + }; + // Only regular files support synchronization. + let FileHandle { file, writable } = + file_descriptor.downcast_ref::<FileHandle>().ok_or_else(|| { + err_unsup_format!( + "`sync_data_range` is only supported on file-backed file descriptors" + ) + })?; + let io_result = maybe_sync_file(file, *writable, File::sync_data); + Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } fn readlink( @@ -1720,7 +1313,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // "returns 1 if fd is an open file descriptor referring to a terminal; // otherwise 0 is returned, and errno is set to indicate the error" let fd = this.read_scalar(miri_fd)?.to_i32()?; - let error = if let Some(fd) = this.machine.file_handler.handles.get(&fd) { + let error = if let Some(fd) = this.machine.fds.get(fd) { if fd.is_tty(this.machine.communicate()) { return Ok(Scalar::from_i32(1)); } else { @@ -1897,7 +1490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { match file { Ok(f) => { - let fh = &mut this.machine.file_handler; + let fh = &mut this.machine.fds; let fd = fh.insert_fd(Box::new(FileHandle { file: f, writable: true })); return Ok(fd); } @@ -1963,7 +1556,7 @@ impl FileMetadata { ecx: &mut MiriInterpCx<'_, 'tcx>, fd: i32, ) -> InterpResult<'tcx, Option<FileMetadata>> { - let option = ecx.machine.file_handler.handles.get(&fd); + let option = ecx.machine.fds.get(fd); let file = match option { Some(file_descriptor) => &file_descriptor @@ -1974,7 +1567,7 @@ impl FileMetadata { ) })? .file, - None => return ecx.handle_not_found().map(|_: i32| None), + None => return ecx.fd_not_found().map(|_: i32| None), }; let metadata = file.metadata(); diff --git a/src/tools/miri/src/shims/unix/linux/fd.rs b/src/tools/miri/src/shims/unix/linux/epoll.rs index 22fbb6da95a..5161d91ca36 100644 --- a/src/tools/miri/src/shims/unix/linux/fd.rs +++ b/src/tools/miri/src/shims/unix/linux/epoll.rs @@ -1,17 +1,52 @@ -use std::cell::Cell; +use std::io; -use rustc_middle::ty::ScalarInt; +use rustc_data_structures::fx::FxHashMap; +use crate::shims::unix::*; use crate::*; -use epoll::{Epoll, EpollEvent}; -use event::Event; -use socketpair::SocketPair; -use shims::unix::fs::EvalContextExt as _; +/// An `Epoll` file descriptor connects file handles and epoll events +#[derive(Clone, Debug, Default)] +struct Epoll { + /// The file descriptors we are watching, and what we are watching for. + file_descriptors: FxHashMap<i32, EpollEvent>, +} + +/// Epoll Events associate events with data. +/// These fields are currently unused by miri. +/// This matches the `epoll_event` struct defined +/// by the epoll_ctl man page. For more information +/// see the man page: +/// +/// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html> +#[derive(Clone, Debug)] +struct EpollEvent { + #[allow(dead_code)] + events: u32, + /// `Scalar<Provenance>` is used to represent the + /// `epoll_data` type union. + #[allow(dead_code)] + data: Scalar<Provenance>, +} + +impl FileDescriptor for Epoll { + fn name(&self) -> &'static str { + "epoll" + } -pub mod epoll; -pub mod event; -pub mod socketpair; + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { + // FIXME: this is probably wrong -- check if the `dup`ed descriptor truly uses an + // independent event set. + Ok(Box::new(self.clone())) + } + + fn close<'tcx>( + self: Box<Self>, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result<i32>> { + Ok(Ok(0)) + } +} impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { @@ -35,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { throw_unsup_format!("epoll_create1 flags {flags} are not implemented"); } - let fd = this.machine.file_handler.insert_fd(Box::new(Epoll::default())); + let fd = this.machine.fds.insert_fd(Box::new(Epoll::default())); Ok(Scalar::from_i32(fd)) } @@ -79,7 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let data = this.read_scalar(&data)?; let event = EpollEvent { events, data }; - if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { + if let Some(epfd) = this.machine.fds.get_mut(epfd) { let epfd = epfd .downcast_mut::<Epoll>() .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; @@ -87,10 +122,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { epfd.file_descriptors.insert(fd, event); Ok(Scalar::from_i32(0)) } else { - Ok(Scalar::from_i32(this.handle_not_found()?)) + Ok(Scalar::from_i32(this.fd_not_found()?)) } } else if op == epoll_ctl_del { - if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { + if let Some(epfd) = this.machine.fds.get_mut(epfd) { let epfd = epfd .downcast_mut::<Epoll>() .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; @@ -98,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { epfd.file_descriptors.remove(&fd); Ok(Scalar::from_i32(0)) } else { - Ok(Scalar::from_i32(this.handle_not_found()?)) + Ok(Scalar::from_i32(this.fd_not_found()?)) } } else { let einval = this.eval_libc("EINVAL"); @@ -150,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let _maxevents = this.read_scalar(maxevents)?.to_i32()?; let _timeout = this.read_scalar(timeout)?.to_i32()?; - if let Some(epfd) = this.machine.file_handler.handles.get_mut(&epfd) { + if let Some(epfd) = this.machine.fds.get_mut(epfd) { let _epfd = epfd .downcast_mut::<Epoll>() .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; @@ -158,96 +193,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // FIXME return number of events ready when scheme for marking events ready exists throw_unsup_format!("returning ready events from epoll_wait is not yet implemented"); } else { - Ok(Scalar::from_i32(this.handle_not_found()?)) + Ok(Scalar::from_i32(this.fd_not_found()?)) } } - - /// This function creates an `Event` that is used as an event wait/notify mechanism by - /// user-space applications, and by the kernel to notify user-space applications of events. - /// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized - /// with the value specified in the `initval` argument. - /// - /// A new file descriptor referring to the `Event` is returned. The `read`, `write`, `poll`, - /// `select`, and `close` operations can be performed on the file descriptor. For more - /// information on these operations, see the man page linked below. - /// - /// The `flags` are not currently implemented for eventfd. - /// The `flags` may be bitwise ORed to change the behavior of `eventfd`: - /// `EFD_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. - /// `EFD_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the new open file description. - /// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics. - /// - /// <https://linux.die.net/man/2/eventfd> - #[expect(clippy::needless_if)] - fn eventfd( - &mut self, - val: &OpTy<'tcx, Provenance>, - flags: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { - let this = self.eval_context_mut(); - - let val = this.read_scalar(val)?.to_u32()?; - let flags = this.read_scalar(flags)?.to_i32()?; - - let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC"); - let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK"); - let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE"); - - if flags & (efd_cloexec | efd_nonblock | efd_semaphore) == 0 { - throw_unsup_format!("{flags} is unsupported"); - } - // FIXME handle the cloexec and nonblock flags - if flags & efd_cloexec == efd_cloexec {} - if flags & efd_nonblock == efd_nonblock {} - if flags & efd_semaphore == efd_semaphore { - throw_unsup_format!("EFD_SEMAPHORE is unsupported"); - } - - let fh = &mut this.machine.file_handler; - let fd = fh.insert_fd(Box::new(Event { val: Cell::new(val.into()) })); - Ok(Scalar::from_i32(fd)) - } - - /// Currently this function creates new `SocketPair`s without specifying the domain, type, or - /// protocol of the new socket and these are stored in the socket values `sv` argument. - /// - /// This function creates an unnamed pair of connected sockets in the specified domain, of the - /// specified type, and using the optionally specified protocol. - /// - /// The `domain` argument specified a communication domain; this selects the protocol family - /// used for communication. The socket `type` specifies the communication semantics. - /// The `protocol` specifies a particular protocol to use with the socket. Normally there's - /// only a single protocol supported for a particular socket type within a given protocol - /// family, in which case `protocol` can be specified as 0. It is possible that many protocols - /// exist and in that case, a particular protocol must be specified. - /// - /// For more information on the arguments see the socket manpage: - /// <https://linux.die.net/man/2/socket> - /// - /// <https://linux.die.net/man/2/socketpair> - fn socketpair( - &mut self, - domain: &OpTy<'tcx, Provenance>, - type_: &OpTy<'tcx, Provenance>, - protocol: &OpTy<'tcx, Provenance>, - sv: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Scalar<Provenance>> { - let this = self.eval_context_mut(); - - let _domain = this.read_scalar(domain)?.to_i32()?; - let _type_ = this.read_scalar(type_)?.to_i32()?; - let _protocol = this.read_scalar(protocol)?.to_i32()?; - let sv = this.deref_pointer(sv)?; - - let fh = &mut this.machine.file_handler; - let sv0 = fh.insert_fd(Box::new(SocketPair)); - let sv0 = ScalarInt::try_from_int(sv0, sv.layout.size).unwrap(); - let sv1 = fh.insert_fd(Box::new(SocketPair)); - let sv1 = ScalarInt::try_from_int(sv1, sv.layout.size).unwrap(); - - this.write_scalar(sv0, &sv)?; - this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?)?; - - Ok(Scalar::from_i32(0)) - } } diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs new file mode 100644 index 00000000000..0f28b69ac4a --- /dev/null +++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs @@ -0,0 +1,125 @@ +//! Linux `eventfd` implementation. +//! Currently just a stub. +use std::cell::Cell; +use std::io; + +use rustc_middle::ty::TyCtxt; +use rustc_target::abi::Endian; + +use crate::shims::unix::*; +use crate::*; + +/// A kind of file descriptor created by `eventfd`. +/// The `Event` type isn't currently written to by `eventfd`. +/// The interface is meant to keep track of objects associated +/// with a file descriptor. For more information see the man +/// page below: +/// +/// <https://man.netbsd.org/eventfd.2> +#[derive(Debug)] +struct Event { + /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the + /// kernel. This counter is initialized with the value specified in the argument initval. + val: Cell<u64>, +} + +impl FileDescriptor for Event { + fn name(&self) -> &'static str { + "event" + } + + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { + // FIXME: this is wrong, the new and old FD should refer to the same event object! + Ok(Box::new(Event { val: self.val.clone() })) + } + + fn close<'tcx>( + self: Box<Self>, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result<i32>> { + Ok(Ok(0)) + } + + /// A write call adds the 8-byte integer value supplied in + /// its buffer (in native endianness) to the counter. The maximum value that may be + /// stored in the counter is the largest unsigned 64-bit value + /// minus 1 (i.e., 0xfffffffffffffffe). If the addition would + /// cause the counter's value to exceed the maximum, then the + /// write either blocks until a read is performed on the + /// file descriptor, or fails with the error EAGAIN if the + /// file descriptor has been made nonblocking. + + /// A write fails with the error EINVAL if the size of the + /// supplied buffer is less than 8 bytes, or if an attempt is + /// made to write the value 0xffffffffffffffff. + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + tcx: TyCtxt<'tcx>, + ) -> InterpResult<'tcx, io::Result<usize>> { + let v1 = self.val.get(); + let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size + // Convert from target endianness to host endianness. + let num = match tcx.sess.target.endian { + Endian::Little => u64::from_le_bytes(bytes), + Endian::Big => u64::from_be_bytes(bytes), + }; + // FIXME handle blocking when addition results in exceeding the max u64 value + // or fail with EAGAIN if the file descriptor is nonblocking. + let v2 = v1.checked_add(num).unwrap(); + self.val.set(v2); + assert_eq!(8, bytes.len()); + Ok(Ok(8)) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// This function creates an `Event` that is used as an event wait/notify mechanism by + /// user-space applications, and by the kernel to notify user-space applications of events. + /// The `Event` contains an `u64` counter maintained by the kernel. The counter is initialized + /// with the value specified in the `initval` argument. + /// + /// A new file descriptor referring to the `Event` is returned. The `read`, `write`, `poll`, + /// `select`, and `close` operations can be performed on the file descriptor. For more + /// information on these operations, see the man page linked below. + /// + /// The `flags` are not currently implemented for eventfd. + /// The `flags` may be bitwise ORed to change the behavior of `eventfd`: + /// `EFD_CLOEXEC` - Set the close-on-exec (`FD_CLOEXEC`) flag on the new file descriptor. + /// `EFD_NONBLOCK` - Set the `O_NONBLOCK` file status flag on the new open file description. + /// `EFD_SEMAPHORE` - miri does not support semaphore-like semantics. + /// + /// <https://linux.die.net/man/2/eventfd> + fn eventfd( + &mut self, + val: &OpTy<'tcx, Provenance>, + flags: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar<Provenance>> { + let this = self.eval_context_mut(); + + let val = this.read_scalar(val)?.to_u32()?; + let flags = this.read_scalar(flags)?.to_i32()?; + + let efd_cloexec = this.eval_libc_i32("EFD_CLOEXEC"); + let efd_nonblock = this.eval_libc_i32("EFD_NONBLOCK"); + let efd_semaphore = this.eval_libc_i32("EFD_SEMAPHORE"); + + if flags & (efd_cloexec | efd_nonblock | efd_semaphore) != flags { + throw_unsup_format!("eventfd: flag {flags:#x} is unsupported"); + } + if flags & efd_cloexec == efd_cloexec { + // cloexec does nothing as we don't support `exec` + } + if flags & efd_nonblock == efd_nonblock { + // FIXME remember the nonblock flag + } + if flags & efd_semaphore == efd_semaphore { + throw_unsup_format!("eventfd: EFD_SEMAPHORE is unsupported"); + } + + let fd = this.machine.fds.insert_fd(Box::new(Event { val: Cell::new(val.into()) })); + Ok(Scalar::from_i32(fd)) + } +} diff --git a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs b/src/tools/miri/src/shims/unix/linux/fd/epoll.rs deleted file mode 100644 index 8c5aed6def6..00000000000 --- a/src/tools/miri/src/shims/unix/linux/fd/epoll.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::*; - -use crate::shims::unix::fs::FileDescriptor; - -use rustc_data_structures::fx::FxHashMap; -use std::io; - -/// An `Epoll` file descriptor connects file handles and epoll events -#[derive(Clone, Debug, Default)] -pub struct Epoll { - /// The file descriptors we are watching, and what we are watching for. - pub file_descriptors: FxHashMap<i32, EpollEvent>, -} - -/// Epoll Events associate events with data. -/// These fields are currently unused by miri. -/// This matches the `epoll_event` struct defined -/// by the epoll_ctl man page. For more information -/// see the man page: -/// -/// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html> -#[derive(Clone, Debug)] -pub struct EpollEvent { - #[allow(dead_code)] - pub events: u32, - /// `Scalar<Provenance>` is used to represent the - /// `epoll_data` type union. - #[allow(dead_code)] - pub data: Scalar<Provenance>, -} - -impl FileDescriptor for Epoll { - fn name(&self) -> &'static str { - "epoll" - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(self.clone())) - } - - fn close<'tcx>( - self: Box<Self>, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result<i32>> { - Ok(Ok(0)) - } -} diff --git a/src/tools/miri/src/shims/unix/linux/fd/event.rs b/src/tools/miri/src/shims/unix/linux/fd/event.rs deleted file mode 100644 index 49408fda3ae..00000000000 --- a/src/tools/miri/src/shims/unix/linux/fd/event.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::shims::unix::fs::FileDescriptor; - -use rustc_const_eval::interpret::InterpResult; -use rustc_middle::ty::TyCtxt; -use rustc_target::abi::Endian; - -use std::cell::Cell; -use std::io; - -/// A kind of file descriptor created by `eventfd`. -/// The `Event` type isn't currently written to by `eventfd`. -/// The interface is meant to keep track of objects associated -/// with a file descriptor. For more information see the man -/// page below: -/// -/// <https://man.netbsd.org/eventfd.2> -#[derive(Debug)] -pub struct Event { - /// The object contains an unsigned 64-bit integer (uint64_t) counter that is maintained by the - /// kernel. This counter is initialized with the value specified in the argument initval. - pub val: Cell<u64>, -} - -impl FileDescriptor for Event { - fn name(&self) -> &'static str { - "event" - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(Event { val: self.val.clone() })) - } - - fn close<'tcx>( - self: Box<Self>, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result<i32>> { - Ok(Ok(0)) - } - - /// A write call adds the 8-byte integer value supplied in - /// its buffer (in native endianness) to the counter. The maximum value that may be - /// stored in the counter is the largest unsigned 64-bit value - /// minus 1 (i.e., 0xfffffffffffffffe). If the addition would - /// cause the counter's value to exceed the maximum, then the - /// write either blocks until a read is performed on the - /// file descriptor, or fails with the error EAGAIN if the - /// file descriptor has been made nonblocking. - - /// A write fails with the error EINVAL if the size of the - /// supplied buffer is less than 8 bytes, or if an attempt is - /// made to write the value 0xffffffffffffffff. - fn write<'tcx>( - &self, - _communicate_allowed: bool, - bytes: &[u8], - tcx: TyCtxt<'tcx>, - ) -> InterpResult<'tcx, io::Result<usize>> { - let v1 = self.val.get(); - let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size - // Convert from target endianness to host endianness. - let num = match tcx.sess.target.endian { - Endian::Little => u64::from_le_bytes(bytes), - Endian::Big => u64::from_be_bytes(bytes), - }; - // FIXME handle blocking when addition results in exceeding the max u64 value - // or fail with EAGAIN if the file descriptor is nonblocking. - let v2 = v1.checked_add(num).unwrap(); - self.val.set(v2); - assert_eq!(8, bytes.len()); - Ok(Ok(8)) - } -} diff --git a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs b/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs deleted file mode 100644 index 6adae88235f..00000000000 --- a/src/tools/miri/src/shims/unix/linux/fd/socketpair.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::*; - -use crate::shims::unix::fs::FileDescriptor; - -use std::io; - -/// Pair of connected sockets. -/// -/// We currently don't allow sending any data through this pair, so this can be just a dummy. -#[derive(Debug)] -pub struct SocketPair; - -impl FileDescriptor for SocketPair { - fn name(&self) -> &'static str { - "socketpair" - } - - fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { - Ok(Box::new(SocketPair)) - } - - fn close<'tcx>( - self: Box<Self>, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result<i32>> { - Ok(Ok(0)) - } -} diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs index d13ada0f4cf..497e8bee70e 100644 --- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs @@ -3,15 +3,13 @@ use rustc_target::spec::abi::Abi; use crate::machine::SIGRTMAX; use crate::machine::SIGRTMIN; +use crate::shims::unix::*; use crate::*; use shims::foreign_items::EmulateForeignItemResult; -use shims::unix::fs::EvalContextExt as _; -use shims::unix::linux::fd::EvalContextExt as _; +use shims::unix::linux::epoll::EvalContextExt as _; +use shims::unix::linux::eventfd::EvalContextExt as _; use shims::unix::linux::mem::EvalContextExt as _; use shims::unix::linux::sync::futex; -use shims::unix::mem::EvalContextExt as _; -use shims::unix::sync::EvalContextExt as _; -use shims::unix::thread::EvalContextExt as _; pub fn is_dyn_sym(name: &str) -> bool { matches!(name, "getrandom") @@ -31,34 +29,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. match link_name.as_str() { - // errno - "__errno_location" => { - let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; - } - // File related shims (but also see "syscall" below for statx) "readdir64" => { let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64(dirp)?; this.write_scalar(result, dest)?; } - "mmap64" => { - let [addr, length, prot, flags, fd, offset] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let offset = this.read_scalar(offset)?.to_i64()?; - let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?; - this.write_scalar(ptr, dest)?; - } - - // Linux-only "sync_file_range" => { let [fd, offset, nbytes, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(result, dest)?; } + + // epoll, eventfd "epoll_create1" => { let [flag] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.epoll_create1(flag)?; @@ -82,29 +66,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let result = this.eventfd(val, flag)?; this.write_scalar(result, dest)?; } - "mremap" => { - let [old_address, old_size, new_size, flags] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.mremap(old_address, old_size, new_size, flags)?; - this.write_scalar(ptr, dest)?; - } - "socketpair" => { - let [domain, type_, protocol, sv] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - - let result = this.socketpair(domain, type_, protocol, sv)?; - this.write_scalar(result, dest)?; - } - "__libc_current_sigrtmin" => { - let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - - this.write_scalar(Scalar::from_i32(SIGRTMIN), dest)?; - } - "__libc_current_sigrtmax" => { - let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - - this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?; - } // Threading "pthread_condattr_setclock" => { @@ -206,6 +167,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; getrandom(this, ptr, len, flags, dest)?; } + "mmap64" => { + let [addr, length, prot, flags, fd, offset] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let offset = this.read_scalar(offset)?.to_i64()?; + let ptr = this.mmap(addr, length, prot, flags, fd, offset.into())?; + this.write_scalar(ptr, dest)?; + } + "mremap" => { + let [old_address, old_size, new_size, flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let ptr = this.mremap(old_address, old_size, new_size, flags)?; + this.write_scalar(ptr, dest)?; + } + "__errno_location" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let errno_place = this.last_error_place()?; + this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; + } + "__libc_current_sigrtmin" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + this.write_scalar(Scalar::from_i32(SIGRTMIN), dest)?; + } + "__libc_current_sigrtmax" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + + this.write_scalar(Scalar::from_i32(SIGRTMAX), dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/src/tools/miri/src/shims/unix/linux/mod.rs b/src/tools/miri/src/shims/unix/linux/mod.rs index fe18f1a32fd..84b604eb9b8 100644 --- a/src/tools/miri/src/shims/unix/linux/mod.rs +++ b/src/tools/miri/src/shims/unix/linux/mod.rs @@ -1,4 +1,5 @@ -pub mod fd; +pub mod epoll; +pub mod eventfd; pub mod foreign_items; pub mod mem; pub mod sync; diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs index 3af01eb44d8..53a02bf5e0b 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -1,10 +1,9 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; +use crate::shims::unix::*; use crate::*; use shims::foreign_items::EmulateForeignItemResult; -use shims::unix::fs::EvalContextExt as _; -use shims::unix::thread::EvalContextExt as _; pub fn is_dyn_sym(_name: &str) -> bool { false diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs index 638473da02b..2bc41e1a62d 100644 --- a/src/tools/miri/src/shims/unix/mod.rs +++ b/src/tools/miri/src/shims/unix/mod.rs @@ -1,7 +1,9 @@ pub mod foreign_items; +mod fd; mod fs; mod mem; +mod socket; mod sync; mod thread; @@ -9,7 +11,15 @@ mod freebsd; mod linux; mod macos; -pub use fs::{DirHandler, FileHandler}; +pub use fd::{FdTable, FileDescriptor}; +pub use fs::DirTable; +// All the unix-specific extension traits +pub use fd::EvalContextExt as _; +pub use fs::EvalContextExt as _; +pub use mem::EvalContextExt as _; +pub use socket::EvalContextExt as _; +pub use sync::EvalContextExt as _; +pub use thread::EvalContextExt as _; // Make up some constants. const UID: u32 = 1000; diff --git a/src/tools/miri/src/shims/unix/socket.rs b/src/tools/miri/src/shims/unix/socket.rs new file mode 100644 index 00000000000..84ddd746fb5 --- /dev/null +++ b/src/tools/miri/src/shims/unix/socket.rs @@ -0,0 +1,65 @@ +use std::io; + +use crate::shims::unix::*; +use crate::*; + +/// Pair of connected sockets. +/// +/// We currently don't allow sending any data through this pair, so this can be just a dummy. +#[derive(Debug)] +struct SocketPair; + +impl FileDescriptor for SocketPair { + fn name(&self) -> &'static str { + "socketpair" + } + + fn dup(&mut self) -> io::Result<Box<dyn FileDescriptor>> { + Ok(Box::new(SocketPair)) + } + + fn close<'tcx>( + self: Box<Self>, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result<i32>> { + Ok(Ok(0)) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { + /// Currently this function this function is a stub. Eventually we need to + /// properly implement an FD type for sockets and have this function create + /// two sockets and associated FDs such that writing to one will produce + /// data that can be read from the other. + /// + /// For more information on the arguments see the socketpair manpage: + /// <https://linux.die.net/man/2/socketpair> + fn socketpair( + &mut self, + domain: &OpTy<'tcx, Provenance>, + type_: &OpTy<'tcx, Provenance>, + protocol: &OpTy<'tcx, Provenance>, + sv: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar<Provenance>> { + let this = self.eval_context_mut(); + + let _domain = this.read_scalar(domain)?.to_i32()?; + let _type_ = this.read_scalar(type_)?.to_i32()?; + let _protocol = this.read_scalar(protocol)?.to_i32()?; + let sv = this.deref_pointer(sv)?; + + // FIXME: fail on unsupported inputs + + let fds = &mut this.machine.fds; + let sv0 = fds.insert_fd(Box::new(SocketPair)); + let sv0 = Scalar::try_from_int(sv0, sv.layout.size).unwrap(); + let sv1 = fds.insert_fd(Box::new(SocketPair)); + let sv1 = Scalar::try_from_int(sv1, sv.layout.size).unwrap(); + + this.write_scalar(sv0, &sv)?; + this.write_scalar(sv1, &sv.offset(sv.layout.size, sv.layout, this)?)?; + + Ok(Scalar::from_i32(0)) + } +} diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py index 21479bc4d58..cac11dff775 100755 --- a/src/tools/miri/test-cargo-miri/run-test.py +++ b/src/tools/miri/test-cargo-miri/run-test.py @@ -31,11 +31,11 @@ def cargo_miri(cmd, quiet = True): def normalize_stdout(str): str = str.replace("src\\", "src/") # normalize paths across platforms - str = re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) # the time keeps changing, obviously + str = re.sub("finished in \\d+\\.\\d\\ds", "finished in $TIME", str) # the time keeps changing, obviously return str def normalize_stderr(str): - str = re.sub("Preparing a sysroot for Miri \(target: [a-z0-9_-]+\)\.\.\. done\n", "", str) # remove leading cargo-miri setup output + str = re.sub("Preparing a sysroot for Miri \\(target: [a-z0-9_-]+\\)\\.\\.\\. done\n", "", str) # remove leading cargo-miri setup output return str def check_output(actual, path, name): diff --git a/src/tools/miri/tests/extern-so/libcode.version b/src/tools/miri/tests/extern-so/libcode.version deleted file mode 100644 index 0f04b9aaebb..00000000000 --- a/src/tools/miri/tests/extern-so/libcode.version +++ /dev/null @@ -1,9 +0,0 @@ -CODEABI_1.0 { - global: *add_one_int*; - *printer*; - *test_stack_spill*; - *get_unsigned_int*; - *add_int16*; - *add_short_to_long*; - local: *; -}; diff --git a/src/tools/miri/tests/extern-so/libtest.map b/src/tools/miri/tests/extern-so/libtest.map new file mode 100644 index 00000000000..a57a4dc149f --- /dev/null +++ b/src/tools/miri/tests/extern-so/libtest.map @@ -0,0 +1,12 @@ +CODEABI_1.0 { + # Define which symbols to export. + global: + add_one_int; + printer; + test_stack_spill; + get_unsigned_int; + add_int16; + add_short_to_long; + # The rest remains private. + local: *; +}; diff --git a/src/tools/miri/tests/fail/extern_static.stderr b/src/tools/miri/tests/fail/extern_static.stderr index c3de4dadb0a..34bb273f04b 100644 --- a/src/tools/miri/tests/fail/extern_static.stderr +++ b/src/tools/miri/tests/fail/extern_static.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: `extern` static `FOO` from crate `extern_static` is not supported by Miri +error: unsupported operation: extern static `FOO` is not supported by Miri --> $DIR/extern_static.rs:LL:CC | LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; - | ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri + | ^^^ extern static `FOO` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/extern_static_in_const.stderr b/src/tools/miri/tests/fail/extern_static_in_const.stderr index 23f775f2588..45d1632cce2 100644 --- a/src/tools/miri/tests/fail/extern_static_in_const.stderr +++ b/src/tools/miri/tests/fail/extern_static_in_const.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: `extern` static `E` from crate `extern_static_in_const` is not supported by Miri +error: unsupported operation: extern static `E` is not supported by Miri --> $DIR/extern_static_in_const.rs:LL:CC | LL | let _val = X; - | ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri + | ^ extern static `E` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/extern_static_wrong_size.rs b/src/tools/miri/tests/fail/extern_static_wrong_size.rs index 17061f0e5c8..fee3c38c25e 100644 --- a/src/tools/miri/tests/fail/extern_static_wrong_size.rs +++ b/src/tools/miri/tests/fail/extern_static_wrong_size.rs @@ -6,5 +6,5 @@ extern "C" { } fn main() { - let _val = unsafe { environ }; //~ ERROR: /has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/ + let _val = unsafe { environ }; //~ ERROR: /with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/ } diff --git a/src/tools/miri/tests/fail/extern_static_wrong_size.stderr b/src/tools/miri/tests/fail/extern_static_wrong_size.stderr index c935a548f80..27699d780c2 100644 --- a/src/tools/miri/tests/fail/extern_static_wrong_size.stderr +++ b/src/tools/miri/tests/fail/extern_static_wrong_size.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes +error: unsupported operation: extern static `environ` has been declared as `extern_static_wrong_size::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes --> $DIR/extern_static_wrong_size.rs:LL:CC | LL | let _val = unsafe { environ }; - | ^^^^^^^ `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes + | ^^^^^^^ extern static `environ` has been declared as `extern_static_wrong_size::environ` with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr index a4249d2e881..e5dbe749884 100644 --- a/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr +++ b/src/tools/miri/tests/fail/issue-miri-3288-ice-symbolic-alignment-extern-static.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri +error: unsupported operation: extern static `_dispatch_queue_attr_concurrent` is not supported by Miri --> $DIR/issue-miri-3288-ice-symbolic-alignment-extern-static.rs:LL:CC | LL | let _val = *DISPATCH_QUEUE_CONCURRENT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ `extern` static `_dispatch_queue_attr_concurrent` from crate `issue_miri_3288_ice_symbolic_alignment_extern_static` is not supported by Miri + | ^^^^^^^^^^^^^^^^^^^^^^^^^ extern static `_dispatch_queue_attr_concurrent` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: BACKTRACE: diff --git a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs index 3f39dcb4b76..50ef0ceef91 100644 --- a/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs +++ b/src/tools/miri/tests/fail/tree_borrows/spurious_read.rs @@ -89,7 +89,7 @@ fn retagx_retagy_retx_writey_rety() { // - retag `y` protected // - (wait for the other thread to return so that there is no foreign protector when we write) // - attempt a write through `y`. - // - (UB should have occured by now, but the next step would be to + // - (UB should have occurred by now, but the next step would be to // remove `y`'s protector) let thread_y = thread::spawn(move || { let b = (2, by); diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index a75fa4cf986..7e8d1401183 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -1,9 +1,10 @@ -use colored::*; -use regex::bytes::Regex; use std::ffi::OsString; use std::num::NonZeroUsize; use std::path::{Path, PathBuf}; use std::{env, process::Command}; + +use colored::*; +use regex::bytes::Regex; use ui_test::color_eyre::eyre::{Context, Result}; use ui_test::{ status_emitter, CommandBuilder, Config, Format, Match, Mode, OutputConflictHandling, @@ -44,12 +45,15 @@ fn build_so_for_c_ffi_tests() -> PathBuf { // This is to avoid automatically adding `malloc`, etc. // Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/ "-fPIC", - "-Wl,--version-script=tests/extern-so/libcode.version", + "-Wl,--version-script=tests/extern-so/libtest.map", ]) .output() .expect("failed to generate shared object file for testing external C function calls"); if !cc_output.status.success() { - panic!("error in generating shared object file for testing external C function calls"); + panic!( + "error in generating shared object file for testing external C function calls:\n{}", + String::from_utf8_lossy(&cc_output.stderr), + ); } so_file_path } @@ -120,10 +124,10 @@ fn run_tests( config.program.args.push("--target".into()); config.program.args.push(target.into()); - // If we're on linux, and we're testing the extern-so functionality, - // then build the shared object file for testing external C function calls - // and push the relevant compiler flag. - if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") { + // If we're testing the extern-so functionality, then build the shared object file for testing + // external C function calls and push the relevant compiler flag. + if path.starts_with("tests/extern-so/") { + assert!(cfg!(target_os = "linux")); let so_file_path = build_so_for_c_ffi_tests(); let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file="); flag.push(so_file_path.into_os_string()); diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 50ff0d26bbb..5a5b008a7cb 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -1,5 +1,5 @@ use std::env; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::path::Path; use std::process::{Command, Output}; @@ -86,6 +86,45 @@ impl Rustc { self } + /// This flag defers LTO optimizations to the linker. + pub fn linker_plugin_lto(&mut self, option: &str) -> &mut Self { + self.cmd.arg(format!("-Clinker-plugin-lto={option}")); + self + } + + /// Specify what happens when the code panics. + pub fn panic(&mut self, option: &str) -> &mut Self { + self.cmd.arg(format!("-Cpanic={option}")); + self + } + + /// Specify number of codegen units + pub fn codegen_units(&mut self, units: usize) -> &mut Self { + self.cmd.arg(format!("-Ccodegen-units={units}")); + self + } + + /// Specify directory path used for incremental cache + pub fn incremental<P: AsRef<Path>>(&mut self, path: P) -> &mut Self { + let mut arg = OsString::new(); + arg.push("-Cincremental="); + arg.push(path.as_ref()); + self.cmd.arg(&arg); + self + } + + /// Specify error format to use + pub fn error_format(&mut self, format: &str) -> &mut Self { + self.cmd.arg(format!("--error-format={format}")); + self + } + + /// Specify json messages printed by the compiler + pub fn json(&mut self, items: &str) -> &mut Self { + self.cmd.arg(format!("--json={items}")); + self + } + /// Specify target triple. pub fn target(&mut self, target: &str) -> &mut Self { assert!(!target.contains(char::is_whitespace), "target triple cannot contain spaces"); @@ -94,13 +133,7 @@ impl Rustc { } /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. - /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>` - /// is passed (note the space). - pub fn arg(&mut self, arg: &str) -> &mut Self { - assert!( - !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), - "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" - ); + pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self { self.cmd.arg(arg); self } @@ -120,16 +153,7 @@ impl Rustc { } /// Generic command arguments provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. - /// This method will panic if a plain `-Z` or `-C` is passed, or if `-Z <name>` or `-C <name>` - /// is passed (note the space). - pub fn args(&mut self, args: &[&str]) -> &mut Self { - for arg in args { - assert!( - !(["-Z", "-C"].contains(&arg) || arg.starts_with("-Z ") || arg.starts_with("-C ")), - "use `-Zarg` or `-Carg` over split `-Z` `arg` or `-C` `arg`" - ); - } - + pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Self { self.cmd.args(args); self } @@ -171,6 +195,18 @@ impl Rustc { output } + #[track_caller] + pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if output.status.code().unwrap() != code { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } + /// Inspect what the underlying [`Command`] is up to the current construction. pub fn inspect(&mut self, f: impl FnOnce(&Command)) -> &mut Self { f(&self.cmd); diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs index 9607ff02f96..1fb4b589d76 100644 --- a/src/tools/run-make-support/src/rustdoc.rs +++ b/src/tools/run-make-support/src/rustdoc.rs @@ -1,4 +1,5 @@ use std::env; +use std::ffi::OsStr; use std::path::Path; use std::process::{Command, Output}; @@ -58,9 +59,8 @@ impl Rustdoc { self } - /// Fallback argument provider. Consider adding meaningfully named methods instead of using - /// this method. - pub fn arg(&mut self, arg: &str) -> &mut Self { + /// Generic command argument provider. Use `.arg("-Zname")` over `.arg("-Z").arg("arg")`. + pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self { self.cmd.arg(arg); self } @@ -77,4 +77,16 @@ impl Rustdoc { } output } + + #[track_caller] + pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output { + let caller_location = std::panic::Location::caller(); + let caller_line_number = caller_location.line(); + + let output = self.cmd.output().unwrap(); + if output.status.code().unwrap() != code { + handle_failed_output(&format!("{:#?}", self.cmd), output, caller_line_number); + } + output + } } diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 7f220a456a8..10a87f6e698 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -867,6 +867,11 @@ impl Rewrite for ast::Ty { self.span, shape, ), + ast::TyKind::Pat(ref ty, ref pat) => { + let ty = ty.rewrite(context, shape)?; + let pat = pat.rewrite(context, shape)?; + Some(format!("{ty} is {pat}")) + } } } } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index c3ed1ff6891..3914feb3499 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -59,7 +59,6 @@ run-make/emit/Makefile run-make/env-dep-info/Makefile run-make/error-found-staticlib-instead-crate/Makefile run-make/error-writing-dependencies/Makefile -run-make/exit-code/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile @@ -321,7 +320,6 @@ run-make/use-suggestions-rust-2018/Makefile run-make/used-cdylib-macos/Makefile run-make/used/Makefile run-make/valid-print-requests/Makefile -run-make/version/Makefile run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs index 6fc65e56901..39f7e70b693 100644 --- a/src/tools/tidy/src/error_codes.rs +++ b/src/tools/tidy/src/error_codes.rs @@ -71,10 +71,12 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String let path = root_path.join(Path::new(ERROR_CODES_PATH)); let file = fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}")); + let path = path.display(); let mut error_codes = Vec::new(); - for line in file.lines() { + for (line_index, line) in file.lines().enumerate() { + let line_index = line_index + 1; let line = line.trim(); if line.starts_with('E') { @@ -82,39 +84,54 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String // Extract the error code from the line. Emit a fatal error if it is not in the correct // format. - let err_code = if let Some(err_code) = split_line { - err_code.0.to_owned() - } else { + let Some(split_line) = split_line else { errors.push(format!( - "Expected a line with the format `Eabcd: abcd, \ + "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \ but got \"{}\" without a `:` delimiter", line, )); continue; }; + let err_code = split_line.0.to_owned(); + // If this is a duplicate of another error code, emit a fatal error. if error_codes.contains(&err_code) { - errors.push(format!("Found duplicate error code: `{}`", err_code)); + errors.push(format!( + "{path}:{line_index}: Found duplicate error code: `{}`", + err_code + )); continue; } let mut chars = err_code.chars(); - chars.next(); + assert_eq!(chars.next(), Some('E')); let error_num_as_str = chars.as_str(); // Ensure that the line references the correct markdown file. - let expected_filename = format!(" {},", error_num_as_str); - if expected_filename != split_line.unwrap().1 { + let rest = split_line.1.split_once(','); + let Some(rest) = rest else { + errors.push(format!( + "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \ + but got \"{}\" without a `,` delimiter", + line, + )); + continue; + }; + if error_num_as_str != rest.0.trim() { errors.push(format!( - "`{}:` should be followed by `{}` but instead found `{}` in \ + "{path}:{line_index}: `{}:` should be followed by `{},` but instead found `{}` in \ `compiler/rustc_error_codes/src/lib.rs`", err_code, - expected_filename, - split_line.unwrap().1, + error_num_as_str, + split_line.1, )); continue; } + if !rest.1.trim().is_empty() && !rest.1.trim().starts_with("//") { + errors.push(format!("{path}:{line_index}: should only have one error per line")); + continue; + } error_codes.push(err_code); } @@ -146,14 +163,14 @@ fn check_error_codes_docs( return; } - // Make sure that the file is referenced in `error_codes.rs` + // Make sure that the file is referenced in `rustc_error_codes/src/lib.rs` let filename = path.file_name().unwrap().to_str().unwrap().split_once('.'); let err_code = filename.unwrap().0; // `unwrap` is ok because we know the filename is in the correct format. if error_codes.iter().all(|e| e != err_code) { errors.push(format!( "Found valid file `{}` in error code docs directory without corresponding \ - entry in `error_code.rs`", + entry in `rustc_error_codes/src/lib.rs`", path.display() )); return; diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 874c15ce41d..e14932ad99d 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -1,4377 +1,4371 @@ - -/* ============================================================ ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️ ============================================================ -*/ -[ -"ui/abi/issue-28676.rs", -"ui/abi/issues/issue-22565-rust-call.rs", -"ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs", -"ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs", -"ui/argument-suggestions/issue-100154.rs", -"ui/argument-suggestions/issue-100478.rs", -"ui/argument-suggestions/issue-101097.rs", -"ui/argument-suggestions/issue-109425.rs", -"ui/argument-suggestions/issue-109831.rs", -"ui/argument-suggestions/issue-112507.rs", -"ui/argument-suggestions/issue-96638.rs", -"ui/argument-suggestions/issue-97197.rs", -"ui/argument-suggestions/issue-97484.rs", -"ui/argument-suggestions/issue-98894.rs", -"ui/argument-suggestions/issue-98897.rs", -"ui/argument-suggestions/issue-99482.rs", -"ui/array-slice-vec/issue-15730.rs", -"ui/array-slice-vec/issue-18425.rs", -"ui/array-slice-vec/issue-69103-extra-binding-subslice.rs", -"ui/asm/issue-113788.rs", -"ui/asm/issue-72570.rs", -"ui/asm/issue-85247.rs", -"ui/asm/issue-87802.rs", -"ui/asm/issue-89305.rs", -"ui/asm/issue-92378.rs", -"ui/asm/issue-97490.rs", -"ui/asm/issue-99071.rs", -"ui/asm/issue-99122-2.rs", -"ui/asm/issue-99122.rs", -"ui/asm/x86_64/issue-82869.rs", -"ui/asm/x86_64/issue-89875.rs", -"ui/asm/x86_64/issue-96797.rs", -"ui/associated-consts/issue-102335-const.rs", -"ui/associated-consts/issue-105330.rs", -"ui/associated-consts/issue-110933.rs", -"ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs", -"ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.rs", -"ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs", -"ui/associated-consts/issue-47814.rs", -"ui/associated-consts/issue-58022.rs", -"ui/associated-consts/issue-63496.rs", -"ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs", -"ui/associated-consts/issue-88599-ref-self.rs", -"ui/associated-consts/issue-93775.rs", -"ui/associated-consts/issue-93835.rs", -"ui/associated-inherent-types/issue-104260.rs", -"ui/associated-inherent-types/issue-109071.rs", -"ui/associated-inherent-types/issue-109299-1.rs", -"ui/associated-inherent-types/issue-109299.rs", -"ui/associated-inherent-types/issue-109768.rs", -"ui/associated-inherent-types/issue-109789.rs", -"ui/associated-inherent-types/issue-109790.rs", -"ui/associated-inherent-types/issue-111404-0.rs", -"ui/associated-inherent-types/issue-111404-1.rs", -"ui/associated-inherent-types/issue-111879-0.rs", -"ui/associated-inherent-types/issue-111879-1.rs", -"ui/associated-item/issue-105449.rs", -"ui/associated-item/issue-48027.rs", -"ui/associated-item/issue-87638.rs", -"ui/associated-type-bounds/issue-102335-ty.rs", -"ui/associated-type-bounds/issue-104916.rs", -"ui/associated-type-bounds/issue-61752.rs", -"ui/associated-type-bounds/issue-70292.rs", -"ui/associated-type-bounds/issue-71443-1.rs", -"ui/associated-type-bounds/issue-71443-2.rs", -"ui/associated-type-bounds/issue-73818.rs", -"ui/associated-type-bounds/issue-79949.rs", -"ui/associated-type-bounds/issue-81193.rs", -"ui/associated-type-bounds/issue-83017.rs", -"ui/associated-type-bounds/issue-99828.rs", -"ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs", -"ui/associated-types/issue-18655.rs", -"ui/associated-types/issue-19081.rs", -"ui/associated-types/issue-19883.rs", -"ui/associated-types/issue-20005.rs", -"ui/associated-types/issue-20825-2.rs", -"ui/associated-types/issue-20825.rs", -"ui/associated-types/issue-21363.rs", -"ui/associated-types/issue-21726.rs", -"ui/associated-types/issue-22037.rs", -"ui/associated-types/issue-22066.rs", -"ui/associated-types/issue-22560.rs", -"ui/associated-types/issue-22828.rs", -"ui/associated-types/issue-23208.rs", -"ui/associated-types/issue-23595-1.rs", -"ui/associated-types/issue-23595-2.rs", -"ui/associated-types/issue-24159.rs", -"ui/associated-types/issue-24204.rs", -"ui/associated-types/issue-24338.rs", -"ui/associated-types/issue-25339.rs", -"ui/associated-types/issue-25700-1.rs", -"ui/associated-types/issue-25700-2.rs", -"ui/associated-types/issue-25700.rs", -"ui/associated-types/issue-26262.rs", -"ui/associated-types/issue-26681.rs", -"ui/associated-types/issue-27675-unchecked-bounds.rs", -"ui/associated-types/issue-27901.rs", -"ui/associated-types/issue-28871.rs", -"ui/associated-types/issue-31597.rs", -"ui/associated-types/issue-32323.rs", -"ui/associated-types/issue-32350.rs", -"ui/associated-types/issue-36499.rs", -"ui/associated-types/issue-37808.rs", -"ui/associated-types/issue-37883.rs", -"ui/associated-types/issue-38821.rs", -"ui/associated-types/issue-38917.rs", -"ui/associated-types/issue-39532.rs", -"ui/associated-types/issue-40093.rs", -"ui/associated-types/issue-41868.rs", -"ui/associated-types/issue-43475.rs", -"ui/associated-types/issue-43784-associated-type.rs", -"ui/associated-types/issue-43924.rs", -"ui/associated-types/issue-44153.rs", -"ui/associated-types/issue-47139-1.rs", -"ui/associated-types/issue-47139-2.rs", -"ui/associated-types/issue-47385.rs", -"ui/associated-types/issue-47814.rs", -"ui/associated-types/issue-48010.rs", -"ui/associated-types/issue-48551.rs", -"ui/associated-types/issue-50301.rs", -"ui/associated-types/issue-54108.rs", -"ui/associated-types/issue-54182-1.rs", -"ui/associated-types/issue-54182-2.rs", -"ui/associated-types/issue-54467.rs", -"ui/associated-types/issue-55846.rs", -"ui/associated-types/issue-59324.rs", -"ui/associated-types/issue-62200.rs", -"ui/associated-types/issue-63591.rs", -"ui/associated-types/issue-63593.rs", -"ui/associated-types/issue-64848.rs", -"ui/associated-types/issue-64855-2.rs", -"ui/associated-types/issue-64855.rs", -"ui/associated-types/issue-65774-1.rs", -"ui/associated-types/issue-65774-2.rs", -"ui/associated-types/issue-65934.rs", -"ui/associated-types/issue-67684.rs", -"ui/associated-types/issue-69398.rs", -"ui/associated-types/issue-71113.rs", -"ui/associated-types/issue-72806.rs", -"ui/associated-types/issue-76179.rs", -"ui/associated-types/issue-82079.rs", -"ui/associated-types/issue-85103-layout-debug.rs", -"ui/associated-types/issue-87261.rs", -"ui/associated-types/issue-88856.rs", -"ui/associated-types/issue-91069.rs", -"ui/associated-types/issue-91231.rs", -"ui/associated-types/issue-91234.rs", -"ui/async-await/auxiliary/issue-107036.rs", -"ui/async-await/auxiliary/issue-72470-lib.rs", -"ui/async-await/in-trait/issue-102138.rs", -"ui/async-await/in-trait/issue-102219.rs", -"ui/async-await/in-trait/issue-102310.rs", -"ui/async-await/in-trait/issue-104678.rs", -"ui/async-await/issue-101715.rs", -"ui/async-await/issue-105501.rs", -"ui/async-await/issue-107036.rs", -"ui/async-await/issue-108572.rs", -"ui/async-await/issue-54239-private-type-triggers-lint.rs", -"ui/async-await/issue-60709.rs", -"ui/async-await/issue-61076.rs", -"ui/async-await/issue-61452.rs", -"ui/async-await/issue-61793.rs", -"ui/async-await/issue-62658.rs", -"ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs", -"ui/async-await/issue-63832-await-short-temporary-lifetime.rs", -"ui/async-await/issue-64130-1-sync.rs", -"ui/async-await/issue-64130-2-send.rs", -"ui/async-await/issue-64130-3-other.rs", -"ui/async-await/issue-64130-4-async-move.rs", -"ui/async-await/issue-64130-non-send-future-diags.rs", -"ui/async-await/issue-64391.rs", -"ui/async-await/issue-65634-raw-ident-suggestion.rs", -"ui/async-await/issue-66312.rs", -"ui/async-await/issue-66387-if-without-else.rs", -"ui/async-await/issue-67252-unnamed-future.rs", -"ui/async-await/issue-67651.rs", -"ui/async-await/issue-67765-async-diagnostic.rs", -"ui/async-await/issue-68112.rs", -"ui/async-await/issue-68523-start.rs", -"ui/async-await/issue-68523.rs", -"ui/async-await/issue-69446-fnmut-capture.rs", -"ui/async-await/issue-70594.rs", -"ui/async-await/issue-70818.rs", -"ui/async-await/issue-70935-complex-spans.rs", -"ui/async-await/issue-71137.rs", -"ui/async-await/issue-72442.rs", -"ui/async-await/issue-72470-llvm-dominate.rs", -"ui/async-await/issue-72590-type-error-sized.rs", -"ui/async-await/issue-73050.rs", -"ui/async-await/issue-73137.rs", -"ui/async-await/issue-73541-1.rs", -"ui/async-await/issue-73541-2.rs", -"ui/async-await/issue-73541-3.rs", -"ui/async-await/issue-73541.rs", -"ui/async-await/issue-73741-type-err.rs", -"ui/async-await/issue-74047.rs", -"ui/async-await/issue-74072-lifetime-name-annotations.rs", -"ui/async-await/issue-74497-lifetime-in-opaque.rs", -"ui/async-await/issue-75785-confusing-named-region.rs", -"ui/async-await/issue-76547.rs", -"ui/async-await/issue-77993-2.rs", -"ui/async-await/issue-78115.rs", -"ui/async-await/issue-84841.rs", -"ui/async-await/issue-86507.rs", -"ui/async-await/issue-93197.rs", -"ui/async-await/issue-93648.rs", -"ui/async-await/issue-98634.rs", -"ui/async-await/issues/auxiliary/issue-60674.rs", -"ui/async-await/issues/auxiliary/issue_67893.rs", -"ui/async-await/issues/issue-102206.rs", -"ui/async-await/issues/issue-107280.rs", -"ui/async-await/issues/issue-112225-1.rs", -"ui/async-await/issues/issue-112225-2.rs", -"ui/async-await/issues/issue-51719.rs", -"ui/async-await/issues/issue-51751.rs", -"ui/async-await/issues/issue-53249.rs", -"ui/async-await/issues/issue-54752-async-block.rs", -"ui/async-await/issues/issue-54974.rs", -"ui/async-await/issues/issue-55324.rs", -"ui/async-await/issues/issue-55809.rs", -"ui/async-await/issues/issue-58885.rs", -"ui/async-await/issues/issue-59001.rs", -"ui/async-await/issues/issue-59972.rs", -"ui/async-await/issues/issue-60518.rs", -"ui/async-await/issues/issue-60655-latebound-regions.rs", -"ui/async-await/issues/issue-60674.rs", -"ui/async-await/issues/issue-61187.rs", -"ui/async-await/issues/issue-61986.rs", -"ui/async-await/issues/issue-62009-1.rs", -"ui/async-await/issues/issue-62009-2.rs", -"ui/async-await/issues/issue-62097.rs", -"ui/async-await/issues/issue-62517-1.rs", -"ui/async-await/issues/issue-62517-2.rs", -"ui/async-await/issues/issue-63388-1.rs", -"ui/async-await/issues/issue-63388-2.rs", -"ui/async-await/issues/issue-63388-3.rs", -"ui/async-await/issues/issue-63388-4.rs", -"ui/async-await/issues/issue-64391-2.rs", -"ui/async-await/issues/issue-64433.rs", -"ui/async-await/issues/issue-64477-2.rs", -"ui/async-await/issues/issue-64477.rs", -"ui/async-await/issues/issue-64964.rs", -"ui/async-await/issues/issue-65159.rs", -"ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs", -"ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs", -"ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs", -"ui/async-await/issues/issue-65436-raw-ptr-not-send.rs", -"ui/async-await/issues/issue-66695-static-refs.rs", -"ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs", -"ui/async-await/issues/issue-67611-static-mut-refs.rs", -"ui/async-await/issues/issue-67893.rs", -"ui/async-await/issues/issue-69307-nested.rs", -"ui/async-await/issues/issue-69307.rs", -"ui/async-await/issues/issue-72312.rs", -"ui/async-await/issues/issue-78600.rs", -"ui/async-await/issues/issue-78654.rs", -"ui/async-await/issues/issue-78938-async-block.rs", -"ui/async-await/issues/issue-95307.rs", -"ui/async-await/return-type-notation/issue-110963-early.rs", -"ui/async-await/return-type-notation/issue-110963-late.rs", -"ui/async-await/track-caller/issue-105134.rs", -"ui/attributes/issue-100631.rs", -"ui/attributes/issue-105594-invalid-attr-validation.rs", -"ui/attributes/issue-115264-expr-field.rs", -"ui/attributes/issue-115264-pat-field.rs", -"ui/attributes/issue-40962.rs", -"ui/attributes/issue-90873.rs", -"ui/auto-traits/issue-117789.rs", -"ui/auto-traits/issue-23080-2.rs", -"ui/auto-traits/issue-23080.rs", -"ui/auto-traits/issue-83857-ub.rs", -"ui/auto-traits/issue-84075.rs", -"ui/auxiliary/issue-13560-1.rs", -"ui/auxiliary/issue-13560-2.rs", -"ui/auxiliary/issue-13560-3.rs", -"ui/auxiliary/issue-16822.rs", -"ui/auxiliary/issue-18502.rs", -"ui/auxiliary/issue-24106.rs", -"ui/auxiliary/issue-76387.rs", -"ui/bench/issue-32062.rs", -"ui/binding/issue-53114-borrow-checks.rs", -"ui/binding/issue-53114-safety-checks.rs", -"ui/binop/issue-25916.rs", -"ui/binop/issue-28837.rs", -"ui/binop/issue-3820.rs", -"ui/binop/issue-62375.rs", -"ui/binop/issue-77910-1.rs", -"ui/binop/issue-77910-2.rs", -"ui/binop/issue-93927.rs", -"ui/block-result/issue-11714.rs", -"ui/block-result/issue-13428.rs", -"ui/block-result/issue-13624.rs", -"ui/block-result/issue-20862.rs", -"ui/block-result/issue-22645.rs", -"ui/block-result/issue-3563.rs", -"ui/block-result/issue-5500.rs", -"ui/borrowck/issue-101119.rs", -"ui/borrowck/issue-102209.rs", -"ui/borrowck/issue-103095.rs", -"ui/borrowck/issue-103250.rs", -"ui/borrowck/issue-103624.rs", -"ui/borrowck/issue-104639-lifetime-order.rs", -"ui/borrowck/issue-10876.rs", -"ui/borrowck/issue-109271-pass-self-into-closure.rs", -"ui/borrowck/issue-111554.rs", -"ui/borrowck/issue-114374-invalid-help-fmt-args.rs", -"ui/borrowck/issue-11493.rs", -"ui/borrowck/issue-115259-suggest-iter-mut.rs", -"ui/borrowck/issue-119915-bad-clone-suggestion.rs", -"ui/borrowck/issue-17263.rs", -"ui/borrowck/issue-17545.rs", -"ui/borrowck/issue-17718-static-move.rs", -"ui/borrowck/issue-20801.rs", -"ui/borrowck/issue-23338-params-outlive-temps-of-body.rs", -"ui/borrowck/issue-24267-flow-exit.rs", -"ui/borrowck/issue-25793.rs", -"ui/borrowck/issue-28934.rs", -"ui/borrowck/issue-29166.rs", -"ui/borrowck/issue-31287-drop-in-guard.rs", -"ui/borrowck/issue-33819.rs", -"ui/borrowck/issue-36082.rs", -"ui/borrowck/issue-41962.rs", -"ui/borrowck/issue-42344.rs", -"ui/borrowck/issue-45199.rs", -"ui/borrowck/issue-45983.rs", -"ui/borrowck/issue-46095.rs", -"ui/borrowck/issue-46471.rs", -"ui/borrowck/issue-47215-ice-from-drop-elab.rs", -"ui/borrowck/issue-47646.rs", -"ui/borrowck/issue-51117.rs", -"ui/borrowck/issue-51301.rs", -"ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs", -"ui/borrowck/issue-51415.rs", -"ui/borrowck/issue-52713-bug.rs", -"ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs", -"ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs", -"ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs", -"ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs", -"ui/borrowck/issue-54499-field-mutation-of-moved-out.rs", -"ui/borrowck/issue-54499-field-mutation-of-never-init.rs", -"ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs", -"ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs", -"ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs", -"ui/borrowck/issue-58776-borrowck-scans-children.rs", -"ui/borrowck/issue-62007-assign-box.rs", -"ui/borrowck/issue-62007-assign-field.rs", -"ui/borrowck/issue-62107-match-arm-scopes.rs", -"ui/borrowck/issue-62387-suggest-iter-mut-2.rs", -"ui/borrowck/issue-62387-suggest-iter-mut.rs", -"ui/borrowck/issue-64453.rs", -"ui/borrowck/issue-69789-iterator-mut-suggestion.rs", -"ui/borrowck/issue-70919-drop-in-loop.rs", -"ui/borrowck/issue-71546.rs", -"ui/borrowck/issue-7573.rs", -"ui/borrowck/issue-80772.rs", -"ui/borrowck/issue-81365-1.rs", -"ui/borrowck/issue-81365-10.rs", -"ui/borrowck/issue-81365-11.rs", -"ui/borrowck/issue-81365-2.rs", -"ui/borrowck/issue-81365-3.rs", -"ui/borrowck/issue-81365-4.rs", -"ui/borrowck/issue-81365-5.rs", -"ui/borrowck/issue-81365-6.rs", -"ui/borrowck/issue-81365-7.rs", -"ui/borrowck/issue-81365-8.rs", -"ui/borrowck/issue-81365-9.rs", -"ui/borrowck/issue-81899.rs", -"ui/borrowck/issue-82032.rs", -"ui/borrowck/issue-82126-mismatched-subst-and-hir.rs", -"ui/borrowck/issue-82462.rs", -"ui/borrowck/issue-83309-ice-immut-in-for-loop.rs", -"ui/borrowck/issue-83760.rs", -"ui/borrowck/issue-83924.rs", -"ui/borrowck/issue-85581.rs", -"ui/borrowck/issue-85765-closure.rs", -"ui/borrowck/issue-85765.rs", -"ui/borrowck/issue-87456-point-to-closure.rs", -"ui/borrowck/issue-88434-minimal-example.rs", -"ui/borrowck/issue-88434-removal-index-should-be-less.rs", -"ui/borrowck/issue-91206.rs", -"ui/borrowck/issue-92015.rs", -"ui/borrowck/issue-92157.rs", -"ui/borrowck/issue-93078.rs", -"ui/borrowck/issue-93093.rs", -"ui/borrowck/issue-95079-missing-move-in-nested-closure.rs", -"ui/box/issue-82446.rs", -"ui/box/issue-95036.rs", -"ui/c-variadic/issue-32201.rs", -"ui/c-variadic/issue-86053-1.rs", -"ui/c-variadic/issue-86053-2.rs", -"ui/cast/issue-106883-is-empty.rs", -"ui/cast/issue-10991.rs", -"ui/cast/issue-17444.rs", -"ui/cast/issue-84213.rs", -"ui/cast/issue-85586.rs", -"ui/cast/issue-88621.rs", -"ui/cast/issue-89497.rs", -"ui/closure-expected-type/issue-24421.rs", -"ui/closure_context/issue-26046-fn-mut.rs", -"ui/closure_context/issue-26046-fn-once.rs", -"ui/closure_context/issue-42065.rs", -"ui/closures/2229_closure_analysis/issue-118144.rs", -"ui/closures/2229_closure_analysis/issue-87378.rs", -"ui/closures/2229_closure_analysis/issue-87987.rs", -"ui/closures/2229_closure_analysis/issue-88118-2.rs", -"ui/closures/2229_closure_analysis/issue-88476.rs", -"ui/closures/2229_closure_analysis/issue-89606.rs", -"ui/closures/2229_closure_analysis/issue-90465.rs", -"ui/closures/2229_closure_analysis/issue-92724-needsdrop-query-cycle.rs", -"ui/closures/2229_closure_analysis/issue_88118.rs", -"ui/closures/2229_closure_analysis/match/issue-87097.rs", -"ui/closures/2229_closure_analysis/match/issue-87426.rs", -"ui/closures/2229_closure_analysis/match/issue-87988.rs", -"ui/closures/2229_closure_analysis/match/issue-88331.rs", -"ui/closures/2229_closure_analysis/migrations/issue-78720.rs", -"ui/closures/2229_closure_analysis/migrations/issue-86753.rs", -"ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-87378.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-88372.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-88431.rs", -"ui/closures/2229_closure_analysis/run_pass/issue-88476.rs", -"ui/closures/issue-101696.rs", -"ui/closures/issue-102089-multiple-opaque-cast.rs", -"ui/closures/issue-10398.rs", -"ui/closures/issue-10682.rs", -"ui/closures/issue-109188.rs", -"ui/closures/issue-111932.rs", -"ui/closures/issue-113087.rs", -"ui/closures/issue-11873.rs", -"ui/closures/issue-1460.rs", -"ui/closures/issue-23012-supertrait-signature-inference.rs", -"ui/closures/issue-25439.rs", -"ui/closures/issue-41366.rs", -"ui/closures/issue-42463.rs", -"ui/closures/issue-46742.rs", -"ui/closures/issue-48109.rs", -"ui/closures/issue-52437.rs", -"ui/closures/issue-67123.rs", -"ui/closures/issue-6801.rs", -"ui/closures/issue-68025.rs", -"ui/closures/issue-72408-nested-closures-exponential.rs", -"ui/closures/issue-78720.rs", -"ui/closures/issue-80313-mutable-borrow-in-closure.rs", -"ui/closures/issue-80313-mutable-borrow-in-move-closure.rs", -"ui/closures/issue-80313-mutation-in-closure.rs", -"ui/closures/issue-80313-mutation-in-move-closure.rs", -"ui/closures/issue-81700-mut-borrow.rs", -"ui/closures/issue-82438-mut-without-upvar.rs", -"ui/closures/issue-84044-drop-non-mut.rs", -"ui/closures/issue-84128.rs", -"ui/closures/issue-868.rs", -"ui/closures/issue-87461.rs", -"ui/closures/issue-87814-1.rs", -"ui/closures/issue-87814-2.rs", -"ui/closures/issue-90871.rs", -"ui/closures/issue-97607.rs", -"ui/closures/issue-99565.rs", -"ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs", -"ui/codegen/auxiliary/issue-97708-aux.rs", -"ui/codegen/issue-101585-128bit-repeat.rs", -"ui/codegen/issue-16602-1.rs", -"ui/codegen/issue-16602-2.rs", -"ui/codegen/issue-16602-3.rs", -"ui/codegen/issue-27859.rs", -"ui/codegen/issue-28950.rs", -"ui/codegen/issue-55976.rs", -"ui/codegen/issue-63787.rs", -"ui/codegen/issue-64401.rs", -"ui/codegen/issue-79865-llvm-miscompile.rs", -"ui/codegen/issue-82833-slice-miscompile.rs", -"ui/codegen/issue-82859-slice-miscompile.rs", -"ui/codegen/issue-88043-bb-does-not-have-terminator.rs", -"ui/codegen/issue-97708.rs", -"ui/codegen/issue-99551.rs", -"ui/codemap_tests/issue-11715.rs", -"ui/codemap_tests/issue-28308.rs", -"ui/coercion/auxiliary/issue-39823.rs", -"ui/coercion/issue-101066.rs", -"ui/coercion/issue-14589.rs", -"ui/coercion/issue-26905-rpass.rs", -"ui/coercion/issue-26905.rs", -"ui/coercion/issue-36007.rs", -"ui/coercion/issue-37655.rs", -"ui/coercion/issue-3794.rs", -"ui/coercion/issue-39823.rs", -"ui/coercion/issue-53475.rs", -"ui/coercion/issue-73886.rs", -"ui/coercion/issue-88097.rs", -"ui/coherence/issue-85026.rs", -"ui/coherence/issue-99663-2.rs", -"ui/coherence/issue-99663.rs", -"ui/command/issue-10626.rs", -"ui/compare-method/issue-90444.rs", -"ui/conditional-compilation/issue-34028.rs", -"ui/confuse-field-and-method/issue-18343.rs", -"ui/confuse-field-and-method/issue-2392.rs", -"ui/confuse-field-and-method/issue-32128.rs", -"ui/confuse-field-and-method/issue-33784.rs", -"ui/const-generics/generic_arg_infer/issue-91614.rs", -"ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs", -"ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs", -"ui/const-generics/generic_const_exprs/issue-100217.rs", -"ui/const-generics/generic_const_exprs/issue-100360.rs", -"ui/const-generics/generic_const_exprs/issue-102074.rs", -"ui/const-generics/generic_const_exprs/issue-102768.rs", -"ui/const-generics/generic_const_exprs/issue-105257.rs", -"ui/const-generics/generic_const_exprs/issue-105608.rs", -"ui/const-generics/generic_const_exprs/issue-109141.rs", -"ui/const-generics/generic_const_exprs/issue-62504.rs", -"ui/const-generics/generic_const_exprs/issue-69654.rs", -"ui/const-generics/generic_const_exprs/issue-72787.rs", -"ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.rs", -"ui/const-generics/generic_const_exprs/issue-73298.rs", -"ui/const-generics/generic_const_exprs/issue-73899.rs", -"ui/const-generics/generic_const_exprs/issue-74634.rs", -"ui/const-generics/generic_const_exprs/issue-74713.rs", -"ui/const-generics/generic_const_exprs/issue-76595.rs", -"ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs", -"ui/const-generics/generic_const_exprs/issue-80561-incorrect-param-env.rs", -"ui/const-generics/generic_const_exprs/issue-80742.rs", -"ui/const-generics/generic_const_exprs/issue-82268.rs", -"ui/const-generics/generic_const_exprs/issue-83765.rs", -"ui/const-generics/generic_const_exprs/issue-83972.rs", -"ui/const-generics/generic_const_exprs/issue-84408.rs", -"ui/const-generics/generic_const_exprs/issue-84669.rs", -"ui/const-generics/generic_const_exprs/issue-85848.rs", -"ui/const-generics/generic_const_exprs/issue-86710.rs", -"ui/const-generics/generic_const_exprs/issue-89851.rs", -"ui/const-generics/generic_const_exprs/issue-90847.rs", -"ui/const-generics/generic_const_exprs/issue-94287.rs", -"ui/const-generics/generic_const_exprs/issue-94293.rs", -"ui/const-generics/generic_const_exprs/issue-96699.rs", -"ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs", -"ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs", -"ui/const-generics/generic_const_exprs/issue-99647.rs", -"ui/const-generics/generic_const_exprs/issue-99705.rs", -"ui/const-generics/infer/issue-77092.rs", -"ui/const-generics/issue-102124.rs", -"ui/const-generics/issue-105689.rs", -"ui/const-generics/issue-106419-struct-with-multiple-const-params.rs", -"ui/const-generics/issue-112505-overflow.rs", -"ui/const-generics/issue-46511.rs", -"ui/const-generics/issue-66451.rs", -"ui/const-generics/issue-70408.rs", -"ui/const-generics/issue-80471.rs", -"ui/const-generics/issue-93647.rs", -"ui/const-generics/issue-97007.rs", -"ui/const-generics/issues/issue-100313.rs", -"ui/const-generics/issues/issue-105037.rs", -"ui/const-generics/issues/issue-105821.rs", -"ui/const-generics/issues/issue-56445-1.rs", -"ui/const-generics/issues/issue-56445-2.rs", -"ui/const-generics/issues/issue-56445-3.rs", -"ui/const-generics/issues/issue-60818-struct-constructors.rs", -"ui/const-generics/issues/issue-61336-1.rs", -"ui/const-generics/issues/issue-61336-2.rs", -"ui/const-generics/issues/issue-61336.rs", -"ui/const-generics/issues/issue-61422.rs", -"ui/const-generics/issues/issue-61432.rs", -"ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs", -"ui/const-generics/issues/issue-62878.rs", -"ui/const-generics/issues/issue-63322-forbid-dyn.rs", -"ui/const-generics/issues/issue-64519.rs", -"ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs", -"ui/const-generics/issues/issue-66906.rs", -"ui/const-generics/issues/issue-67185-1.rs", -"ui/const-generics/issues/issue-67185-2.rs", -"ui/const-generics/issues/issue-67375.rs", -"ui/const-generics/issues/issue-67739.rs", -"ui/const-generics/issues/issue-67945-1.rs", -"ui/const-generics/issues/issue-67945-2.rs", -"ui/const-generics/issues/issue-67945-3.rs", -"ui/const-generics/issues/issue-67945-4.rs", -"ui/const-generics/issues/issue-68104-print-stack-overflow.rs", -"ui/const-generics/issues/issue-68366.rs", -"ui/const-generics/issues/issue-68596.rs", -"ui/const-generics/issues/issue-68615-adt.rs", -"ui/const-generics/issues/issue-68615-array.rs", -"ui/const-generics/issues/issue-69654-run-pass.rs", -"ui/const-generics/issues/issue-70125-1.rs", -"ui/const-generics/issues/issue-70125-2.rs", -"ui/const-generics/issues/issue-70167.rs", -"ui/const-generics/issues/issue-70180-1-stalled_on.rs", -"ui/const-generics/issues/issue-70180-2-stalled_on.rs", -"ui/const-generics/issues/issue-70225.rs", -"ui/const-generics/issues/issue-70273-assoc-fn.rs", -"ui/const-generics/issues/issue-71169.rs", -"ui/const-generics/issues/issue-71202.rs", -"ui/const-generics/issues/issue-71381.rs", -"ui/const-generics/issues/issue-71382.rs", -"ui/const-generics/issues/issue-71547.rs", -"ui/const-generics/issues/issue-71611.rs", -"ui/const-generics/issues/issue-71986.rs", -"ui/const-generics/issues/issue-72352.rs", -"ui/const-generics/issues/issue-72845.rs", -"ui/const-generics/issues/issue-73120.rs", -"ui/const-generics/issues/issue-73260.rs", -"ui/const-generics/issues/issue-73491.rs", -"ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs", -"ui/const-generics/issues/issue-74101.rs", -"ui/const-generics/issues/issue-74255.rs", -"ui/const-generics/issues/issue-74906.rs", -"ui/const-generics/issues/issue-74950.rs", -"ui/const-generics/issues/issue-75047.rs", -"ui/const-generics/issues/issue-75299.rs", -"ui/const-generics/issues/issue-76701-ty-param-in-const.rs", -"ui/const-generics/issues/issue-79674.rs", -"ui/const-generics/issues/issue-80062.rs", -"ui/const-generics/issues/issue-80375.rs", -"ui/const-generics/issues/issue-82956.rs", -"ui/const-generics/issues/issue-83249.rs", -"ui/const-generics/issues/issue-83288.rs", -"ui/const-generics/issues/issue-83466.rs", -"ui/const-generics/issues/issue-83765.rs", -"ui/const-generics/issues/issue-84659.rs", -"ui/const-generics/issues/issue-85031-2.rs", -"ui/const-generics/issues/issue-86033.rs", -"ui/const-generics/issues/issue-86530.rs", -"ui/const-generics/issues/issue-86535-2.rs", -"ui/const-generics/issues/issue-86535.rs", -"ui/const-generics/issues/issue-86820.rs", -"ui/const-generics/issues/issue-87076.rs", -"ui/const-generics/issues/issue-87470.rs", -"ui/const-generics/issues/issue-87493.rs", -"ui/const-generics/issues/issue-87964.rs", -"ui/const-generics/issues/issue-88119.rs", -"ui/const-generics/issues/issue-88468.rs", -"ui/const-generics/issues/issue-88997.rs", -"ui/const-generics/issues/issue-89146.rs", -"ui/const-generics/issues/issue-89304.rs", -"ui/const-generics/issues/issue-89320.rs", -"ui/const-generics/issues/issue-89334.rs", -"ui/const-generics/issues/issue-90318.rs", -"ui/const-generics/issues/issue-90364.rs", -"ui/const-generics/issues/issue-90455.rs", -"ui/const-generics/issues/issue-92186.rs", -"ui/const-generics/issues/issue-96654.rs", -"ui/const-generics/issues/issue-97278.rs", -"ui/const-generics/issues/issue-97634.rs", -"ui/const-generics/issues/issue-98629.rs", -"ui/const-generics/issues/issue-99641.rs", -"ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs", -"ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs", -"ui/const-generics/parser-error-recovery/issue-89013-type.rs", -"ui/const-generics/parser-error-recovery/issue-89013.rs", -"ui/const-generics/type-dependent/issue-61936.rs", -"ui/const-generics/type-dependent/issue-63695.rs", -"ui/const-generics/type-dependent/issue-67144-1.rs", -"ui/const-generics/type-dependent/issue-67144-2.rs", -"ui/const-generics/type-dependent/issue-69816.rs", -"ui/const-generics/type-dependent/issue-70217.rs", -"ui/const-generics/type-dependent/issue-70507.rs", -"ui/const-generics/type-dependent/issue-70586.rs", -"ui/const-generics/type-dependent/issue-71348.rs", -"ui/const-generics/type-dependent/issue-71382.rs", -"ui/const-generics/type-dependent/issue-71805.rs", -"ui/const-generics/type-dependent/issue-73730.rs", -"ui/const_prop/issue-102553.rs", -"ui/const_prop/issue-86351.rs", -"ui/consts/auxiliary/issue-17718-aux.rs", -"ui/consts/auxiliary/issue-63226.rs", -"ui/consts/const-eval/issue-100878.rs", -"ui/consts/const-eval/issue-104390.rs", -"ui/consts/const-eval/issue-114994-fail.rs", -"ui/consts/const-eval/issue-114994.rs", -"ui/consts/const-eval/issue-43197.rs", -"ui/consts/const-eval/issue-44578.rs", -"ui/consts/const-eval/issue-47971.rs", -"ui/consts/const-eval/issue-49296.rs", -"ui/consts/const-eval/issue-50706.rs", -"ui/consts/const-eval/issue-50814-2.rs", -"ui/consts/const-eval/issue-50814.rs", -"ui/consts/const-eval/issue-51300.rs", -"ui/consts/const-eval/issue-52475.rs", -"ui/consts/const-eval/issue-53157.rs", -"ui/consts/const-eval/issue-53401.rs", -"ui/consts/const-eval/issue-55541.rs", -"ui/consts/const-eval/issue-64908.rs", -"ui/consts/const-eval/issue-64970.rs", -"ui/consts/const-eval/issue-65394.rs", -"ui/consts/const-eval/issue-70723.rs", -"ui/consts/const-eval/issue-70804-fn-subtyping.rs", -"ui/consts/const-eval/issue-84957-const-str-as-bytes.rs", -"ui/consts/const-eval/issue-85155.rs", -"ui/consts/const-eval/issue-85907.rs", -"ui/consts/const-eval/issue-91827-extern-types-field-offset.rs", -"ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs", -"ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs", -"ui/consts/const-mut-refs/issue-76510.rs", -"ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.rs", -"ui/consts/const_in_pattern/issue-44333.rs", -"ui/consts/const_in_pattern/issue-53708.rs", -"ui/consts/const_in_pattern/issue-62614.rs", -"ui/consts/const_in_pattern/issue-65466.rs", -"ui/consts/const_in_pattern/issue-73431.rs", -"ui/consts/control-flow/issue-46843.rs", -"ui/consts/control-flow/issue-50577.rs", -"ui/consts/extra-const-ub/issue-100771.rs", -"ui/consts/extra-const-ub/issue-101034.rs", -"ui/consts/issue-102117.rs", -"ui/consts/issue-103790.rs", -"ui/consts/issue-104155.rs", -"ui/consts/issue-104396.rs", -"ui/consts/issue-104609.rs", -"ui/consts/issue-104768.rs", -"ui/consts/issue-105536-const-val-roundtrip-ptr-eq.rs", -"ui/consts/issue-116186.rs", -"ui/consts/issue-13837.rs", -"ui/consts/issue-13902.rs", -"ui/consts/issue-16538.rs", -"ui/consts/issue-17074.rs", -"ui/consts/issue-17458.rs", -"ui/consts/issue-17718-borrow-interior.rs", -"ui/consts/issue-17718-const-bad-values.rs", -"ui/consts/issue-17718-const-borrow.rs", -"ui/consts/issue-17718-constants-not-static.rs", -"ui/consts/issue-17718-references.rs", -"ui/consts/issue-17718.rs", -"ui/consts/issue-17756.rs", -"ui/consts/issue-18294.rs", -"ui/consts/issue-19244.rs", -"ui/consts/issue-21562.rs", -"ui/consts/issue-21721.rs", -"ui/consts/issue-23833.rs", -"ui/consts/issue-23968-const-not-overflow.rs", -"ui/consts/issue-25826.rs", -"ui/consts/issue-27890.rs", -"ui/consts/issue-28113.rs", -"ui/consts/issue-28822.rs", -"ui/consts/issue-29798.rs", -"ui/consts/issue-29914-2.rs", -"ui/consts/issue-29914-3.rs", -"ui/consts/issue-29914.rs", -"ui/consts/issue-29927-1.rs", -"ui/consts/issue-29927.rs", -"ui/consts/issue-32829-2.rs", -"ui/consts/issue-32829.rs", -"ui/consts/issue-33537.rs", -"ui/consts/issue-33903.rs", -"ui/consts/issue-3521.rs", -"ui/consts/issue-36163.rs", -"ui/consts/issue-37222.rs", -"ui/consts/issue-37550-1.rs", -"ui/consts/issue-37550.rs", -"ui/consts/issue-37991.rs", -"ui/consts/issue-39161-bogus-error.rs", -"ui/consts/issue-39974.rs", -"ui/consts/issue-43105.rs", -"ui/consts/issue-44255.rs", -"ui/consts/issue-44415.rs", -"ui/consts/issue-46553.rs", -"ui/consts/issue-47789.rs", -"ui/consts/issue-50439.rs", -"ui/consts/issue-52023-array-size-pointer-cast.rs", -"ui/consts/issue-52060.rs", -"ui/consts/issue-54224.rs", -"ui/consts/issue-54348.rs", -"ui/consts/issue-54387.rs", -"ui/consts/issue-54582.rs", -"ui/consts/issue-54954.rs", -"ui/consts/issue-56164.rs", -"ui/consts/issue-58435-ice-with-assoc-const.rs", -"ui/consts/issue-62045.rs", -"ui/consts/issue-63226.rs", -"ui/consts/issue-63952.rs", -"ui/consts/issue-64059.rs", -"ui/consts/issue-64506.rs", -"ui/consts/issue-64662.rs", -"ui/consts/issue-65348.rs", -"ui/consts/issue-66342.rs", -"ui/consts/issue-66345.rs", -"ui/consts/issue-66397.rs", -"ui/consts/issue-66693-panic-in-array-len.rs", -"ui/consts/issue-66693.rs", -"ui/consts/issue-66787.rs", -"ui/consts/issue-67529.rs", -"ui/consts/issue-67640.rs", -"ui/consts/issue-67641.rs", -"ui/consts/issue-67696-const-prop-ice.rs", -"ui/consts/issue-67862.rs", -"ui/consts/issue-68264-overflow.rs", -"ui/consts/issue-68542-closure-in-array-len.rs", -"ui/consts/issue-68684.rs", -"ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs", -"ui/consts/issue-69310-array-size-lit-wrong-ty.rs", -"ui/consts/issue-69312.rs", -"ui/consts/issue-69488.rs", -"ui/consts/issue-69532.rs", -"ui/consts/issue-6991.rs", -"ui/consts/issue-70773-mir-typeck-lt-norm.rs", -"ui/consts/issue-70942-trait-vs-impl-mismatch.rs", -"ui/consts/issue-73976-monomorphic.rs", -"ui/consts/issue-73976-polymorphic.rs", -"ui/consts/issue-76064.rs", -"ui/consts/issue-77062-large-zst-array.rs", -"ui/consts/issue-78655.rs", -"ui/consts/issue-79137-monomorphic.rs", -"ui/consts/issue-79137-toogeneric.rs", -"ui/consts/issue-79152-const-array-index.rs", -"ui/consts/issue-79690.rs", -"ui/consts/issue-87046.rs", -"ui/consts/issue-88071.rs", -"ui/consts/issue-88649.rs", -"ui/consts/issue-89088.rs", -"ui/consts/issue-90762.rs", -"ui/consts/issue-90870.rs", -"ui/consts/issue-90878-2.rs", -"ui/consts/issue-90878-3.rs", -"ui/consts/issue-90878.rs", -"ui/consts/issue-91434.rs", -"ui/consts/issue-91560.rs", -"ui/consts/issue-94371.rs", -"ui/consts/issue-94675.rs", -"ui/consts/issue-96169.rs", -"ui/coroutine/issue-102645.rs", -"ui/coroutine/issue-105084.rs", -"ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs", -"ui/coroutine/issue-113279.rs", -"ui/coroutine/issue-44197.rs", -"ui/coroutine/issue-45729-unsafe-in-coroutine.rs", -"ui/coroutine/issue-48048.rs", -"ui/coroutine/issue-52304.rs", -"ui/coroutine/issue-52398.rs", -"ui/coroutine/issue-53548-1.rs", -"ui/coroutine/issue-53548.rs", -"ui/coroutine/issue-57017.rs", -"ui/coroutine/issue-57084.rs", -"ui/coroutine/issue-57478.rs", -"ui/coroutine/issue-58888.rs", -"ui/coroutine/issue-61442-stmt-expr-with-drop.rs", -"ui/coroutine/issue-62506-two_awaits.rs", -"ui/coroutine/issue-64620-yield-array-element.rs", -"ui/coroutine/issue-68112.rs", -"ui/coroutine/issue-69017.rs", -"ui/coroutine/issue-69039.rs", -"ui/coroutine/issue-87142.rs", -"ui/coroutine/issue-88653.rs", -"ui/coroutine/issue-91477.rs", -"ui/coroutine/issue-93161.rs", -"ui/cross-crate/issue-64872/issue-64872.rs", -"ui/cycle-trait/issue-12511.rs", -"ui/debuginfo/issue-105386-debuginfo-ub.rs", -"ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs", -"ui/deprecation/issue-84637-deprecated-associated-function.rs", -"ui/derived-errors/issue-30580.rs", -"ui/derived-errors/issue-31997-1.rs", -"ui/derived-errors/issue-31997.rs", -"ui/derives/issue-36617.rs", -"ui/derives/issue-43023.rs", -"ui/derives/issue-91492.rs", -"ui/derives/issue-91550.rs", -"ui/derives/issue-97343.rs", -"ui/deriving/issue-103157.rs", -"ui/deriving/issue-15689-1.rs", -"ui/deriving/issue-15689-2.rs", -"ui/deriving/issue-18738.rs", -"ui/deriving/issue-19358.rs", -"ui/deriving/issue-3935.rs", -"ui/deriving/issue-58319.rs", -"ui/deriving/issue-6341.rs", -"ui/deriving/issue-89188-gat-hrtb.rs", -"ui/did_you_mean/issue-103909.rs", -"ui/did_you_mean/issue-105225-named-args.rs", -"ui/did_you_mean/issue-105225.rs", -"ui/did_you_mean/issue-114112.rs", -"ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.rs", -"ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.rs", -"ui/did_you_mean/issue-31424.rs", -"ui/did_you_mean/issue-34126.rs", -"ui/did_you_mean/issue-34337.rs", -"ui/did_you_mean/issue-35937.rs", -"ui/did_you_mean/issue-36798.rs", -"ui/did_you_mean/issue-36798_unknown_field.rs", -"ui/did_you_mean/issue-37139.rs", -"ui/did_you_mean/issue-38054-do-not-show-unresolved-names.rs", -"ui/did_you_mean/issue-38147-1.rs", -"ui/did_you_mean/issue-38147-2.rs", -"ui/did_you_mean/issue-38147-3.rs", -"ui/did_you_mean/issue-38147-4.rs", -"ui/did_you_mean/issue-39544.rs", -"ui/did_you_mean/issue-39802-show-5-trait-impls.rs", -"ui/did_you_mean/issue-40006.rs", -"ui/did_you_mean/issue-40396.rs", -"ui/did_you_mean/issue-40823.rs", -"ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.rs", -"ui/did_you_mean/issue-42599_available_fields_note.rs", -"ui/did_you_mean/issue-42764.rs", -"ui/did_you_mean/issue-43871-enum-instead-of-variant.rs", -"ui/did_you_mean/issue-46718-struct-pattern-dotdotdot.rs", -"ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.rs", -"ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.rs", -"ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs", -"ui/did_you_mean/issue-53280-expected-float-found-integer-literal.rs", -"ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs", -"ui/did_you_mean/issue-54109-without-witness.rs", -"ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs", -"ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs", -"ui/drop/auxiliary/issue-10028.rs", -"ui/drop/issue-100276.rs", -"ui/drop/issue-10028.rs", -"ui/drop/issue-103107.rs", -"ui/drop/issue-110682.rs", -"ui/drop/issue-17718-const-destructors.rs", -"ui/drop/issue-21486.rs", -"ui/drop/issue-23338-ensure-param-drop-order.rs", -"ui/drop/issue-23611-enum-swap-in-drop.rs", -"ui/drop/issue-2734.rs", -"ui/drop/issue-2735-2.rs", -"ui/drop/issue-2735-3.rs", -"ui/drop/issue-2735.rs", -"ui/drop/issue-30018-nopanic.rs", -"ui/drop/issue-35546.rs", -"ui/drop/issue-48962.rs", -"ui/drop/issue-90752-raw-ptr-shenanigans.rs", -"ui/drop/issue-90752.rs", -"ui/drop/issue-979.rs", -"ui/dropck/issue-24805-dropck-itemless.rs", -"ui/dropck/issue-28498-ugeh-with-lifetime-param.rs", -"ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs", -"ui/dropck/issue-28498-ugeh-with-trait-bound.rs", -"ui/dropck/issue-29844.rs", -"ui/dropck/issue-34053.rs", -"ui/dropck/issue-38868.rs", -"ui/dropck/issue-54943-1.rs", -"ui/dropck/issue-54943-2.rs", -"ui/dst/issue-113447.rs", -"ui/dst/issue-90528-unsizing-not-suggestion-110063.rs", -"ui/dst/issue-90528-unsizing-suggestion-1.rs", -"ui/dst/issue-90528-unsizing-suggestion-2.rs", -"ui/dst/issue-90528-unsizing-suggestion-3.rs", -"ui/dst/issue-90528-unsizing-suggestion-4.rs", -"ui/dyn-keyword/issue-5153.rs", -"ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs", -"ui/dyn-star/issue-102430.rs", -"ui/empty/issue-37026.rs", -"ui/entry-point/issue-118772.rs", -"ui/enum-discriminant/auxiliary/issue-41394.rs", -"ui/enum-discriminant/issue-104519.rs", -"ui/enum-discriminant/issue-41394-rpass.rs", -"ui/enum-discriminant/issue-41394.rs", -"ui/enum-discriminant/issue-43398.rs", -"ui/enum-discriminant/issue-46519.rs", -"ui/enum-discriminant/issue-50689.rs", -"ui/enum-discriminant/issue-51582.rs", -"ui/enum-discriminant/issue-61696.rs", -"ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs", -"ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs", -"ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs", -"ui/enum-discriminant/issue-70509-partial_eq.rs", -"ui/enum-discriminant/issue-72554.rs", -"ui/enum-discriminant/issue-90038.rs", -"ui/enum/issue-1821.rs", -"ui/enum/issue-42747.rs", -"ui/enum/issue-67945-1.rs", -"ui/enum/issue-67945-2.rs", -"ui/error-codes/e0119/auxiliary/issue-23563-a.rs", -"ui/error-codes/e0119/issue-23563.rs", -"ui/error-codes/e0119/issue-27403.rs", -"ui/error-codes/e0119/issue-28981.rs", -"ui/errors/issue-104621-extern-bad-file.rs", -"ui/errors/issue-104621-extern-not-file.rs", -"ui/errors/issue-89280-emitter-overflow-splice-lines.rs", -"ui/errors/issue-99572-impl-trait-on-pointer.rs", -"ui/expr/if/issue-4201.rs", -"ui/extern/auxiliary/issue-80074-macro-2.rs", -"ui/extern/auxiliary/issue-80074-macro.rs", -"ui/extern/issue-10025.rs", -"ui/extern/issue-10763.rs", -"ui/extern/issue-10764-rpass.rs", -"ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs", -"ui/extern/issue-116203.rs", -"ui/extern/issue-1251.rs", -"ui/extern/issue-13655.rs", -"ui/extern/issue-16250.rs", -"ui/extern/issue-18576.rs", -"ui/extern/issue-18819.rs", -"ui/extern/issue-28324.rs", -"ui/extern/issue-36122-accessing-externed-dst.rs", -"ui/extern/issue-47725.rs", -"ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs", -"ui/extern/issue-64655-extern-rust-must-allow-unwind.rs", -"ui/extern/issue-80074.rs", -"ui/extern/issue-95829.rs", -"ui/feature-gates/issue-43106-gating-of-bench.rs", -"ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs", -"ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs", -"ui/feature-gates/issue-43106-gating-of-deprecated.rs", -"ui/feature-gates/issue-43106-gating-of-derive-2.rs", -"ui/feature-gates/issue-43106-gating-of-derive.rs", -"ui/feature-gates/issue-43106-gating-of-macro_escape.rs", -"ui/feature-gates/issue-43106-gating-of-macro_use.rs", -"ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs", -"ui/feature-gates/issue-43106-gating-of-stable.rs", -"ui/feature-gates/issue-43106-gating-of-test.rs", -"ui/feature-gates/issue-43106-gating-of-unstable.rs", -"ui/feature-gates/issue-49983-see-issue-0.rs", -"ui/fmt/issue-103826.rs", -"ui/fmt/issue-104142.rs", -"ui/fmt/issue-23781.rs", -"ui/fmt/issue-75307.rs", -"ui/fmt/issue-86085.rs", -"ui/fmt/issue-89173.rs", -"ui/fmt/issue-91556.rs", -"ui/fn/issue-1451.rs", -"ui/fn/issue-1900.rs", -"ui/fn/issue-3044.rs", -"ui/fn/issue-3099.rs", -"ui/fn/issue-3904.rs", -"ui/fn/issue-39259.rs", -"ui/fn/issue-80179.rs", -"ui/for-loop-while/issue-1257.rs", -"ui/for-loop-while/issue-2216.rs", -"ui/for-loop-while/issue-51345.rs", -"ui/for-loop-while/issue-69841.rs", -"ui/for/issue-20605.rs", -"ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs", -"ui/foreign/issue-91370-foreign-fn-block-impl.rs", -"ui/foreign/issue-99276-same-type-lifetimes.rs", -"ui/function-pointer/issue-102289.rs", -"ui/functions-closures/closure-expected-type/issue-38714.rs", -"ui/generic-associated-types/bugs/issue-100013.rs", -"ui/generic-associated-types/bugs/issue-80626.rs", -"ui/generic-associated-types/bugs/issue-87735.rs", -"ui/generic-associated-types/bugs/issue-87755.rs", -"ui/generic-associated-types/bugs/issue-87803.rs", -"ui/generic-associated-types/bugs/issue-88382.rs", -"ui/generic-associated-types/bugs/issue-88460.rs", -"ui/generic-associated-types/bugs/issue-88526.rs", -"ui/generic-associated-types/bugs/issue-91762.rs", -"ui/generic-associated-types/issue-101020.rs", -"ui/generic-associated-types/issue-102114.rs", -"ui/generic-associated-types/issue-102333.rs", -"ui/generic-associated-types/issue-102335-gat.rs", -"ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs", -"ui/generic-associated-types/issue-47206-where-clause.rs", -"ui/generic-associated-types/issue-58694-parameter-out-of-range.rs", -"ui/generic-associated-types/issue-62326-parameter-out-of-range.rs", -"ui/generic-associated-types/issue-67424.rs", -"ui/generic-associated-types/issue-67510-pass.rs", -"ui/generic-associated-types/issue-67510.rs", -"ui/generic-associated-types/issue-68641-check-gat-bounds.rs", -"ui/generic-associated-types/issue-68642-broken-llvm-ir.rs", -"ui/generic-associated-types/issue-68643-broken-mir.rs", -"ui/generic-associated-types/issue-68644-codegen-selection.rs", -"ui/generic-associated-types/issue-68645-codegen-fulfillment.rs", -"ui/generic-associated-types/issue-68648-1.rs", -"ui/generic-associated-types/issue-68648-2.rs", -"ui/generic-associated-types/issue-68649-pass.rs", -"ui/generic-associated-types/issue-68653.rs", -"ui/generic-associated-types/issue-68656-unsized-values.rs", -"ui/generic-associated-types/issue-70303.rs", -"ui/generic-associated-types/issue-70304.rs", -"ui/generic-associated-types/issue-71176.rs", -"ui/generic-associated-types/issue-74684-1.rs", -"ui/generic-associated-types/issue-74684-2.rs", -"ui/generic-associated-types/issue-74816.rs", -"ui/generic-associated-types/issue-74824.rs", -"ui/generic-associated-types/issue-76407.rs", -"ui/generic-associated-types/issue-76535.rs", -"ui/generic-associated-types/issue-76826.rs", -"ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs", -"ui/generic-associated-types/issue-78671.rs", -"ui/generic-associated-types/issue-79422.rs", -"ui/generic-associated-types/issue-79636-1.rs", -"ui/generic-associated-types/issue-79636-2.rs", -"ui/generic-associated-types/issue-80433-reduced.rs", -"ui/generic-associated-types/issue-80433.rs", -"ui/generic-associated-types/issue-81487.rs", -"ui/generic-associated-types/issue-81712-cyclic-traits.rs", -"ui/generic-associated-types/issue-81862.rs", -"ui/generic-associated-types/issue-84931.rs", -"ui/generic-associated-types/issue-85921.rs", -"ui/generic-associated-types/issue-86218-2.rs", -"ui/generic-associated-types/issue-86218.rs", -"ui/generic-associated-types/issue-86483.rs", -"ui/generic-associated-types/issue-86787.rs", -"ui/generic-associated-types/issue-87258_a.rs", -"ui/generic-associated-types/issue-87258_b.rs", -"ui/generic-associated-types/issue-87429-2.rs", -"ui/generic-associated-types/issue-87429-associated-type-default.rs", -"ui/generic-associated-types/issue-87429-specialization.rs", -"ui/generic-associated-types/issue-87429.rs", -"ui/generic-associated-types/issue-87748.rs", -"ui/generic-associated-types/issue-87750.rs", -"ui/generic-associated-types/issue-88287.rs", -"ui/generic-associated-types/issue-88360.rs", -"ui/generic-associated-types/issue-88405.rs", -"ui/generic-associated-types/issue-88459.rs", -"ui/generic-associated-types/issue-88595.rs", -"ui/generic-associated-types/issue-89008.rs", -"ui/generic-associated-types/issue-89352.rs", -"ui/generic-associated-types/issue-90014-tait.rs", -"ui/generic-associated-types/issue-90014-tait2.rs", -"ui/generic-associated-types/issue-90014.rs", -"ui/generic-associated-types/issue-90729.rs", -"ui/generic-associated-types/issue-91139.rs", -"ui/generic-associated-types/issue-91883.rs", -"ui/generic-associated-types/issue-92033.rs", -"ui/generic-associated-types/issue-92096.rs", -"ui/generic-associated-types/issue-92280.rs", -"ui/generic-associated-types/issue-92954.rs", -"ui/generic-associated-types/issue-93141.rs", -"ui/generic-associated-types/issue-93262.rs", -"ui/generic-associated-types/issue-93341.rs", -"ui/generic-associated-types/issue-93342.rs", -"ui/generic-associated-types/issue-93874.rs", -"ui/generic-associated-types/issue-95305.rs", -"ui/generics/issue-106694.rs", -"ui/generics/issue-1112.rs", -"ui/generics/issue-2936.rs", -"ui/generics/issue-32498.rs", -"ui/generics/issue-333.rs", -"ui/generics/issue-59508-1.rs", -"ui/generics/issue-59508.rs", -"ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs", -"ui/generics/issue-61631-default-type-param-cannot-reference-self.rs", -"ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs", -"ui/generics/issue-79605.rs", -"ui/generics/issue-80512-param-reordering-with-defaults.rs", -"ui/generics/issue-83556.rs", -"ui/generics/issue-94432-garbage-ice.rs", -"ui/generics/issue-94923.rs", -"ui/generics/issue-95208-ignore-qself.rs", -"ui/generics/issue-95208.rs", -"ui/generics/issue-98432.rs", -"ui/higher-ranked/trait-bounds/issue-100689.rs", -"ui/higher-ranked/trait-bounds/issue-102899.rs", -"ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs", -"ui/higher-ranked/trait-bounds/issue-39292.rs", -"ui/higher-ranked/trait-bounds/issue-42114.rs", -"ui/higher-ranked/trait-bounds/issue-43623.rs", -"ui/higher-ranked/trait-bounds/issue-46989.rs", -"ui/higher-ranked/trait-bounds/issue-57639.rs", -"ui/higher-ranked/trait-bounds/issue-58451.rs", -"ui/higher-ranked/trait-bounds/issue-59311.rs", -"ui/higher-ranked/trait-bounds/issue-60283.rs", -"ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs", -"ui/higher-ranked/trait-bounds/issue-88446.rs", -"ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs", -"ui/higher-ranked/trait-bounds/issue-90177.rs", -"ui/higher-ranked/trait-bounds/issue-95034.rs", -"ui/higher-ranked/trait-bounds/issue-95230.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs", -"ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs", -"ui/hygiene/issue-15221.rs", -"ui/hygiene/issue-29746.rs", -"ui/hygiene/issue-32922.rs", -"ui/hygiene/issue-40847.rs", -"ui/hygiene/issue-44128.rs", -"ui/hygiene/issue-47311.rs", -"ui/hygiene/issue-47312.rs", -"ui/hygiene/issue-61574-const-parameters.rs", -"ui/hygiene/issue-77523-def-site-async-await.rs", -"ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs", -"ui/impl-trait/in-trait/issue-102140.rs", -"ui/impl-trait/in-trait/issue-102301.rs", -"ui/impl-trait/in-trait/issue-102571.rs", -"ui/impl-trait/issue-100075-2.rs", -"ui/impl-trait/issue-100075.rs", -"ui/impl-trait/issue-100187.rs", -"ui/impl-trait/issue-102605.rs", -"ui/impl-trait/issue-103181-1.rs", -"ui/impl-trait/issue-103181-2.rs", -"ui/impl-trait/issue-103599.rs", -"ui/impl-trait/issue-108591.rs", -"ui/impl-trait/issue-108592.rs", -"ui/impl-trait/issue-35668.rs", -"ui/impl-trait/issue-36792.rs", -"ui/impl-trait/issue-46959.rs", -"ui/impl-trait/issue-49556.rs", -"ui/impl-trait/issue-49579.rs", -"ui/impl-trait/issue-49685.rs", -"ui/impl-trait/issue-51185.rs", -"ui/impl-trait/issue-54966.rs", -"ui/impl-trait/issue-55872-1.rs", -"ui/impl-trait/issue-55872-2.rs", -"ui/impl-trait/issue-55872-3.rs", -"ui/impl-trait/issue-55872.rs", -"ui/impl-trait/issue-56445.rs", -"ui/impl-trait/issue-68532.rs", -"ui/impl-trait/issue-72911.rs", -"ui/impl-trait/issue-87450.rs", -"ui/impl-trait/issue-99073-2.rs", -"ui/impl-trait/issue-99073.rs", -"ui/impl-trait/issue-99642-2.rs", -"ui/impl-trait/issue-99642.rs", -"ui/impl-trait/issue-99914.rs", -"ui/impl-trait/issues/issue-104815.rs", -"ui/impl-trait/issues/issue-105826.rs", -"ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs", -"ui/impl-trait/issues/issue-42479.rs", -"ui/impl-trait/issues/issue-49376.rs", -"ui/impl-trait/issues/issue-52128.rs", -"ui/impl-trait/issues/issue-53457.rs", -"ui/impl-trait/issues/issue-54600.rs", -"ui/impl-trait/issues/issue-54840.rs", -"ui/impl-trait/issues/issue-54895.rs", -"ui/impl-trait/issues/issue-55608-captures-empty-region.rs", -"ui/impl-trait/issues/issue-57464-unexpected-regions.rs", -"ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs", -"ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs", -"ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs", -"ui/impl-trait/issues/issue-58504.rs", -"ui/impl-trait/issues/issue-58956.rs", -"ui/impl-trait/issues/issue-62742.rs", -"ui/impl-trait/issues/issue-65581.rs", -"ui/impl-trait/issues/issue-67830.rs", -"ui/impl-trait/issues/issue-70877.rs", -"ui/impl-trait/issues/issue-70971.rs", -"ui/impl-trait/issues/issue-74282.rs", -"ui/impl-trait/issues/issue-77987.rs", -"ui/impl-trait/issues/issue-78722-2.rs", -"ui/impl-trait/issues/issue-78722.rs", -"ui/impl-trait/issues/issue-79099.rs", -"ui/impl-trait/issues/issue-82139.rs", -"ui/impl-trait/issues/issue-83919.rs", -"ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs", -"ui/impl-trait/issues/issue-84073.rs", -"ui/impl-trait/issues/issue-84919.rs", -"ui/impl-trait/issues/issue-86201.rs", -"ui/impl-trait/issues/issue-86642.rs", -"ui/impl-trait/issues/issue-86719.rs", -"ui/impl-trait/issues/issue-86800.rs", -"ui/impl-trait/issues/issue-87295.rs", -"ui/impl-trait/issues/issue-87340.rs", -"ui/impl-trait/issues/issue-88236-2.rs", -"ui/impl-trait/issues/issue-88236.rs", -"ui/impl-trait/issues/issue-89312.rs", -"ui/impl-trait/issues/issue-92305.rs", -"ui/impl-trait/issues/issue-93788.rs", -"ui/impl-trait/issues/issue-99348-impl-compatibility.rs", -"ui/implied-bounds/issue-100690.rs", -"ui/implied-bounds/issue-101951.rs", -"ui/implied-bounds/issue-110161.rs", -"ui/imports/auxiliary/issue-114682-2-extern.rs", -"ui/imports/auxiliary/issue-114682-3-extern.rs", -"ui/imports/auxiliary/issue-114682-4-extern.rs", -"ui/imports/auxiliary/issue-114682-5-extern-1.rs", -"ui/imports/auxiliary/issue-114682-5-extern-2.rs", -"ui/imports/auxiliary/issue-114682-6-extern.rs", -"ui/imports/auxiliary/issue-119369-extern.rs", -"ui/imports/auxiliary/issue-36881-aux.rs", -"ui/imports/auxiliary/issue-52891.rs", -"ui/imports/auxiliary/issue-55811.rs", -"ui/imports/auxiliary/issue-56125.rs", -"ui/imports/auxiliary/issue-59764.rs", -"ui/imports/auxiliary/issue-85992-extern-1.rs", -"ui/imports/auxiliary/issue-85992-extern-2.rs", -"ui/imports/issue-109148.rs", -"ui/imports/issue-109343.rs", -"ui/imports/issue-113953.rs", -"ui/imports/issue-114682-1.rs", -"ui/imports/issue-114682-2.rs", -"ui/imports/issue-114682-3.rs", -"ui/imports/issue-114682-4.rs", -"ui/imports/issue-114682-5.rs", -"ui/imports/issue-114682-6.rs", -"ui/imports/issue-119369.rs", -"ui/imports/issue-13404.rs", -"ui/imports/issue-1697.rs", -"ui/imports/issue-18083.rs", -"ui/imports/issue-19498.rs", -"ui/imports/issue-24081.rs", -"ui/imports/issue-24883.rs", -"ui/imports/issue-25396.rs", -"ui/imports/issue-26873-multifile/issue-26873-multifile.rs", -"ui/imports/issue-26873-multifile/issue-26873-onefile.rs", -"ui/imports/issue-26886.rs", -"ui/imports/issue-26930.rs", -"ui/imports/issue-28134.rs", -"ui/imports/issue-28388-1.rs", -"ui/imports/issue-28388-2.rs", -"ui/imports/issue-2937.rs", -"ui/imports/issue-30560.rs", -"ui/imports/issue-31212.rs", -"ui/imports/issue-32119.rs", -"ui/imports/issue-32222.rs", -"ui/imports/issue-32354-suggest-import-rename.rs", -"ui/imports/issue-32833.rs", -"ui/imports/issue-33464.rs", -"ui/imports/issue-36881.rs", -"ui/imports/issue-37887.rs", -"ui/imports/issue-38293.rs", -"ui/imports/issue-4366-2.rs", -"ui/imports/issue-4366.rs", -"ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs", -"ui/imports/issue-45829/auxiliary/issue-45829-a.rs", -"ui/imports/issue-45829/auxiliary/issue-45829-b.rs", -"ui/imports/issue-45829/issue-45829.rs", -"ui/imports/issue-47623.rs", -"ui/imports/issue-4865-1.rs", -"ui/imports/issue-4865-2.rs", -"ui/imports/issue-4865-3.rs", -"ui/imports/issue-52891.rs", -"ui/imports/issue-53140.rs", -"ui/imports/issue-53269.rs", -"ui/imports/issue-53512.rs", -"ui/imports/issue-53565.rs", -"ui/imports/issue-55457.rs", -"ui/imports/issue-55811.rs", -"ui/imports/issue-55884-1.rs", -"ui/imports/issue-55884-2.rs", -"ui/imports/issue-56125.rs", -"ui/imports/issue-56263.rs", -"ui/imports/issue-57015.rs", -"ui/imports/issue-57539.rs", -"ui/imports/issue-59764.rs", -"ui/imports/issue-62767.rs", -"ui/imports/issue-68103.rs", -"ui/imports/issue-81413.rs", -"ui/imports/issue-8208.rs", -"ui/imports/issue-85992.rs", -"ui/imports/issue-8640.rs", -"ui/imports/issue-99695-b.rs", -"ui/imports/issue-99695.rs", -"ui/inference/issue-103587.rs", -"ui/inference/issue-104649.rs", -"ui/inference/issue-107090.rs", -"ui/inference/issue-113354.rs", -"ui/inference/issue-12028.rs", -"ui/inference/issue-28935.rs", -"ui/inference/issue-36053.rs", -"ui/inference/issue-3743.rs", -"ui/inference/issue-70082.rs", -"ui/inference/issue-70703.rs", -"ui/inference/issue-71309.rs", -"ui/inference/issue-71584.rs", -"ui/inference/issue-71732.rs", -"ui/inference/issue-72616.rs", -"ui/inference/issue-72690.rs", -"ui/inference/issue-80409.rs", -"ui/inference/issue-80816.rs", -"ui/inference/issue-81522.rs", -"ui/inference/issue-83606.rs", -"ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs", -"ui/inference/issue-86162-1.rs", -"ui/inference/issue-86162-2.rs", -"ui/inference/need_type_info/issue-103053.rs", -"ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs", -"ui/inference/need_type_info/issue-109905.rs", -"ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.rs", -"ui/infinite/issue-41731-infinite-macro-print.rs", -"ui/infinite/issue-41731-infinite-macro-println.rs", -"ui/intrinsics/issue-28575.rs", -"ui/intrinsics/issue-84297-reifying-copy.rs", -"ui/invalid/issue-114435-layout-type-err.rs", -"ui/issue-11881.rs", -"ui/issue-13560.rs", -"ui/issue-15924.rs", -"ui/issue-16822.rs", -"ui/issue-18502.rs", -"ui/issue-24106.rs", -"ui/issue-76387-llvm-miscompile.rs", -"ui/issues-71798.rs", -"ui/issues/auxiliary/issue-111011.rs", -"ui/issues/auxiliary/issue-11224.rs", -"ui/issues/auxiliary/issue-11508.rs", -"ui/issues/auxiliary/issue-11529.rs", -"ui/issues/auxiliary/issue-11680.rs", -"ui/issues/auxiliary/issue-12133-dylib.rs", -"ui/issues/auxiliary/issue-12133-dylib2.rs", -"ui/issues/auxiliary/issue-12133-rlib.rs", -"ui/issues/auxiliary/issue-12612-1.rs", -"ui/issues/auxiliary/issue-12612-2.rs", -"ui/issues/auxiliary/issue-12660-aux.rs", -"ui/issues/auxiliary/issue-13507.rs", -"ui/issues/auxiliary/issue-13620-1.rs", -"ui/issues/auxiliary/issue-13620-2.rs", -"ui/issues/auxiliary/issue-13872-1.rs", -"ui/issues/auxiliary/issue-13872-2.rs", -"ui/issues/auxiliary/issue-13872-3.rs", -"ui/issues/auxiliary/issue-14344-1.rs", -"ui/issues/auxiliary/issue-14344-2.rs", -"ui/issues/auxiliary/issue-14421.rs", -"ui/issues/auxiliary/issue-14422.rs", -"ui/issues/auxiliary/issue-15562.rs", -"ui/issues/auxiliary/issue-16643.rs", -"ui/issues/auxiliary/issue-16725.rs", -"ui/issues/auxiliary/issue-17662.rs", -"ui/issues/auxiliary/issue-18501.rs", -"ui/issues/auxiliary/issue-18514.rs", -"ui/issues/auxiliary/issue-18711.rs", -"ui/issues/auxiliary/issue-18913-1.rs", -"ui/issues/auxiliary/issue-18913-2.rs", -"ui/issues/auxiliary/issue-19293.rs", -"ui/issues/auxiliary/issue-19340-1.rs", -"ui/issues/auxiliary/issue-20389.rs", -"ui/issues/auxiliary/issue-21202.rs", -"ui/issues/auxiliary/issue-2170-lib.rs", -"ui/issues/auxiliary/issue-2316-a.rs", -"ui/issues/auxiliary/issue-2316-b.rs", -"ui/issues/auxiliary/issue-2380.rs", -"ui/issues/auxiliary/issue-2414-a.rs", -"ui/issues/auxiliary/issue-2414-b.rs", -"ui/issues/auxiliary/issue-2472-b.rs", -"ui/issues/auxiliary/issue-25185-1.rs", -"ui/issues/auxiliary/issue-25185-2.rs", -"ui/issues/auxiliary/issue-2526.rs", -"ui/issues/auxiliary/issue-25467.rs", -"ui/issues/auxiliary/issue-2631-a.rs", -"ui/issues/auxiliary/issue-2723-a.rs", -"ui/issues/auxiliary/issue-29265.rs", -"ui/issues/auxiliary/issue-29485.rs", -"ui/issues/auxiliary/issue-3012-1.rs", -"ui/issues/auxiliary/issue-30123-aux.rs", -"ui/issues/auxiliary/issue-3136-a.rs", -"ui/issues/auxiliary/issue-31702-1.rs", -"ui/issues/auxiliary/issue-31702-2.rs", -"ui/issues/auxiliary/issue-34796-aux.rs", -"ui/issues/auxiliary/issue-36954.rs", -"ui/issues/auxiliary/issue-38190.rs", -"ui/issues/auxiliary/issue-38226-aux.rs", -"ui/issues/auxiliary/issue-3979-traits.rs", -"ui/issues/auxiliary/issue-41053.rs", -"ui/issues/auxiliary/issue-41549.rs", -"ui/issues/auxiliary/issue-42007-s.rs", -"ui/issues/auxiliary/issue-4208-cc.rs", -"ui/issues/auxiliary/issue-4545.rs", -"ui/issues/auxiliary/issue-48984-aux.rs", -"ui/issues/auxiliary/issue-49544.rs", -"ui/issues/auxiliary/issue-51798.rs", -"ui/issues/auxiliary/issue-52489.rs", -"ui/issues/auxiliary/issue-5518.rs", -"ui/issues/auxiliary/issue-5521.rs", -"ui/issues/auxiliary/issue-56943.rs", -"ui/issues/auxiliary/issue-57271-lib.rs", -"ui/issues/auxiliary/issue-5844-aux.rs", -"ui/issues/auxiliary/issue-7178.rs", -"ui/issues/auxiliary/issue-73112.rs", -"ui/issues/auxiliary/issue-7899.rs", -"ui/issues/auxiliary/issue-8044.rs", -"ui/issues/auxiliary/issue-8259.rs", -"ui/issues/auxiliary/issue-8401.rs", -"ui/issues/auxiliary/issue-9123.rs", -"ui/issues/auxiliary/issue-9155.rs", -"ui/issues/auxiliary/issue-9188.rs", -"ui/issues/auxiliary/issue-9906.rs", -"ui/issues/auxiliary/issue-9968.rs", -"ui/issues/issue-10228.rs", -"ui/issues/issue-10291.rs", -"ui/issues/issue-102964.rs", -"ui/issues/issue-10396.rs", -"ui/issues/issue-10412.rs", -"ui/issues/issue-10436.rs", -"ui/issues/issue-10456.rs", -"ui/issues/issue-10465.rs", -"ui/issues/issue-10545.rs", -"ui/issues/issue-10638.rs", -"ui/issues/issue-10656.rs", -"ui/issues/issue-106755.rs", -"ui/issues/issue-10683.rs", -"ui/issues/issue-10718.rs", -"ui/issues/issue-10734.rs", -"ui/issues/issue-10764.rs", -"ui/issues/issue-10767.rs", -"ui/issues/issue-10802.rs", -"ui/issues/issue-10806.rs", -"ui/issues/issue-10853.rs", -"ui/issues/issue-10877.rs", -"ui/issues/issue-10902.rs", -"ui/issues/issue-11004.rs", -"ui/issues/issue-11047.rs", -"ui/issues/issue-11085.rs", -"ui/issues/issue-11192.rs", -"ui/issues/issue-11205.rs", -"ui/issues/issue-11224.rs", -"ui/issues/issue-11267.rs", -"ui/issues/issue-11374.rs", -"ui/issues/issue-11382.rs", -"ui/issues/issue-11384.rs", -"ui/issues/issue-11508.rs", -"ui/issues/issue-11529.rs", -"ui/issues/issue-11552.rs", -"ui/issues/issue-11592.rs", -"ui/issues/issue-11677.rs", -"ui/issues/issue-11680.rs", -"ui/issues/issue-11681.rs", -"ui/issues/issue-11692-1.rs", -"ui/issues/issue-11692-2.rs", -"ui/issues/issue-11709.rs", -"ui/issues/issue-11740.rs", -"ui/issues/issue-11771.rs", -"ui/issues/issue-11820.rs", -"ui/issues/issue-11844.rs", -"ui/issues/issue-11869.rs", -"ui/issues/issue-11958.rs", -"ui/issues/issue-12033.rs", -"ui/issues/issue-12041.rs", -"ui/issues/issue-12127.rs", -"ui/issues/issue-12133-1.rs", -"ui/issues/issue-12133-2.rs", -"ui/issues/issue-12133-3.rs", -"ui/issues/issue-12187-1.rs", -"ui/issues/issue-12187-2.rs", -"ui/issues/issue-12285.rs", -"ui/issues/issue-12567.rs", -"ui/issues/issue-12612.rs", -"ui/issues/issue-12660.rs", -"ui/issues/issue-12677.rs", -"ui/issues/issue-12699.rs", -"ui/issues/issue-12729.rs", -"ui/issues/issue-12744.rs", -"ui/issues/issue-12860.rs", -"ui/issues/issue-12863.rs", -"ui/issues/issue-12909.rs", -"ui/issues/issue-12920.rs", -"ui/issues/issue-13027.rs", -"ui/issues/issue-13058.rs", -"ui/issues/issue-13105.rs", -"ui/issues/issue-13167.rs", -"ui/issues/issue-13202.rs", -"ui/issues/issue-13204.rs", -"ui/issues/issue-13214.rs", -"ui/issues/issue-13259-windows-tcb-trash.rs", -"ui/issues/issue-13264.rs", -"ui/issues/issue-13323.rs", -"ui/issues/issue-13359.rs", -"ui/issues/issue-13405.rs", -"ui/issues/issue-13407.rs", -"ui/issues/issue-13434.rs", -"ui/issues/issue-13446.rs", -"ui/issues/issue-13466.rs", -"ui/issues/issue-13482-2.rs", -"ui/issues/issue-13482.rs", -"ui/issues/issue-13497-2.rs", -"ui/issues/issue-13497.rs", -"ui/issues/issue-13507-2.rs", -"ui/issues/issue-13620.rs", -"ui/issues/issue-13665.rs", -"ui/issues/issue-13703.rs", -"ui/issues/issue-13763.rs", -"ui/issues/issue-13775.rs", -"ui/issues/issue-13808.rs", -"ui/issues/issue-13847.rs", -"ui/issues/issue-13867.rs", -"ui/issues/issue-13872.rs", -"ui/issues/issue-14082.rs", -"ui/issues/issue-14091-2.rs", -"ui/issues/issue-14091.rs", -"ui/issues/issue-14092.rs", -"ui/issues/issue-14229.rs", -"ui/issues/issue-14254.rs", -"ui/issues/issue-14285.rs", -"ui/issues/issue-14308.rs", -"ui/issues/issue-14330.rs", -"ui/issues/issue-14344.rs", -"ui/issues/issue-14366.rs", -"ui/issues/issue-14382.rs", -"ui/issues/issue-14393.rs", -"ui/issues/issue-14399.rs", -"ui/issues/issue-14421.rs", -"ui/issues/issue-14422.rs", -"ui/issues/issue-14541.rs", -"ui/issues/issue-14721.rs", -"ui/issues/issue-14821.rs", -"ui/issues/issue-14845.rs", -"ui/issues/issue-14853.rs", -"ui/issues/issue-14865.rs", -"ui/issues/issue-14875.rs", -"ui/issues/issue-14901.rs", -"ui/issues/issue-14915.rs", -"ui/issues/issue-14919.rs", -"ui/issues/issue-14959.rs", -"ui/issues/issue-15034.rs", -"ui/issues/issue-15043.rs", -"ui/issues/issue-15063.rs", -"ui/issues/issue-15094.rs", -"ui/issues/issue-15104.rs", -"ui/issues/issue-15129-rpass.rs", -"ui/issues/issue-15167.rs", -"ui/issues/issue-15189.rs", -"ui/issues/issue-15207.rs", -"ui/issues/issue-15260.rs", -"ui/issues/issue-15381.rs", -"ui/issues/issue-15444.rs", -"ui/issues/issue-15523-big.rs", -"ui/issues/issue-15523.rs", -"ui/issues/issue-15562.rs", -"ui/issues/issue-15571.rs", -"ui/issues/issue-15673.rs", -"ui/issues/issue-15734.rs", -"ui/issues/issue-15735.rs", -"ui/issues/issue-15756.rs", -"ui/issues/issue-15763.rs", -"ui/issues/issue-15774.rs", -"ui/issues/issue-15783.rs", -"ui/issues/issue-15793.rs", -"ui/issues/issue-15858.rs", -"ui/issues/issue-15896.rs", -"ui/issues/issue-15965.rs", -"ui/issues/issue-16048.rs", -"ui/issues/issue-16149.rs", -"ui/issues/issue-16151.rs", -"ui/issues/issue-16256.rs", -"ui/issues/issue-16278.rs", -"ui/issues/issue-16401.rs", -"ui/issues/issue-16441.rs", -"ui/issues/issue-16452.rs", -"ui/issues/issue-16492.rs", -"ui/issues/issue-16530.rs", -"ui/issues/issue-16560.rs", -"ui/issues/issue-16562.rs", -"ui/issues/issue-16596.rs", -"ui/issues/issue-16643.rs", -"ui/issues/issue-16648.rs", -"ui/issues/issue-16668.rs", -"ui/issues/issue-16671.rs", -"ui/issues/issue-16683.rs", -"ui/issues/issue-16725.rs", -"ui/issues/issue-16739.rs", -"ui/issues/issue-16745.rs", -"ui/issues/issue-16774.rs", -"ui/issues/issue-16783.rs", -"ui/issues/issue-16819.rs", -"ui/issues/issue-16922-rpass.rs", -"ui/issues/issue-16939.rs", -"ui/issues/issue-16966.rs", -"ui/issues/issue-16994.rs", -"ui/issues/issue-17001.rs", -"ui/issues/issue-17033.rs", -"ui/issues/issue-17068.rs", -"ui/issues/issue-17121.rs", -"ui/issues/issue-17216.rs", -"ui/issues/issue-17252.rs", -"ui/issues/issue-17302.rs", -"ui/issues/issue-17322.rs", -"ui/issues/issue-17336.rs", -"ui/issues/issue-17337.rs", -"ui/issues/issue-17351.rs", -"ui/issues/issue-17361.rs", -"ui/issues/issue-17373.rs", -"ui/issues/issue-17385.rs", -"ui/issues/issue-17405.rs", -"ui/issues/issue-17441.rs", -"ui/issues/issue-17450.rs", -"ui/issues/issue-17503.rs", -"ui/issues/issue-17546.rs", -"ui/issues/issue-17551.rs", -"ui/issues/issue-17651.rs", -"ui/issues/issue-17662.rs", -"ui/issues/issue-17732.rs", -"ui/issues/issue-17734.rs", -"ui/issues/issue-17740.rs", -"ui/issues/issue-17746.rs", -"ui/issues/issue-17758.rs", -"ui/issues/issue-17771.rs", -"ui/issues/issue-17800.rs", -"ui/issues/issue-17816.rs", -"ui/issues/issue-17877.rs", -"ui/issues/issue-17897.rs", -"ui/issues/issue-17904-2.rs", -"ui/issues/issue-17904.rs", -"ui/issues/issue-17905-2.rs", -"ui/issues/issue-17905.rs", -"ui/issues/issue-17933.rs", -"ui/issues/issue-17954.rs", -"ui/issues/issue-17959.rs", -"ui/issues/issue-17994.rs", -"ui/issues/issue-17999.rs", -"ui/issues/issue-18058.rs", -"ui/issues/issue-18088.rs", -"ui/issues/issue-18107.rs", -"ui/issues/issue-18110.rs", -"ui/issues/issue-18119.rs", -"ui/issues/issue-18159.rs", -"ui/issues/issue-18173.rs", -"ui/issues/issue-18183.rs", -"ui/issues/issue-18188.rs", -"ui/issues/issue-18232.rs", -"ui/issues/issue-18352.rs", -"ui/issues/issue-18353.rs", -"ui/issues/issue-18389.rs", -"ui/issues/issue-18423.rs", -"ui/issues/issue-18446-2.rs", -"ui/issues/issue-18446.rs", -"ui/issues/issue-18464.rs", -"ui/issues/issue-18501.rs", -"ui/issues/issue-18514.rs", -"ui/issues/issue-18532.rs", -"ui/issues/issue-18539.rs", -"ui/issues/issue-18566.rs", -"ui/issues/issue-18611.rs", -"ui/issues/issue-18685.rs", -"ui/issues/issue-18711.rs", -"ui/issues/issue-18767.rs", -"ui/issues/issue-18783.rs", -"ui/issues/issue-18809.rs", -"ui/issues/issue-18845.rs", -"ui/issues/issue-18859.rs", -"ui/issues/issue-18906.rs", -"ui/issues/issue-18913.rs", -"ui/issues/issue-18919.rs", -"ui/issues/issue-18952.rs", -"ui/issues/issue-18959.rs", -"ui/issues/issue-18988.rs", -"ui/issues/issue-19001.rs", -"ui/issues/issue-19037.rs", -"ui/issues/issue-19086.rs", -"ui/issues/issue-19097.rs", -"ui/issues/issue-19098.rs", -"ui/issues/issue-19100.rs", -"ui/issues/issue-19127.rs", -"ui/issues/issue-19129-1.rs", -"ui/issues/issue-19129-2.rs", -"ui/issues/issue-19135.rs", -"ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs", -"ui/issues/issue-1920-absolute-paths/issue-1920-1.rs", -"ui/issues/issue-1920-absolute-paths/issue-1920-2.rs", -"ui/issues/issue-1920-absolute-paths/issue-1920-3.rs", -"ui/issues/issue-19244-1.rs", -"ui/issues/issue-19244-2.rs", -"ui/issues/issue-19293.rs", -"ui/issues/issue-19340-1.rs", -"ui/issues/issue-19340-2.rs", -"ui/issues/issue-19367.rs", -"ui/issues/issue-19380.rs", -"ui/issues/issue-19398.rs", -"ui/issues/issue-19404.rs", -"ui/issues/issue-19479.rs", -"ui/issues/issue-19482.rs", -"ui/issues/issue-19499.rs", -"ui/issues/issue-19601.rs", -"ui/issues/issue-19631.rs", -"ui/issues/issue-19632.rs", -"ui/issues/issue-19692.rs", -"ui/issues/issue-19734.rs", -"ui/issues/issue-19811-escape-unicode.rs", -"ui/issues/issue-19850.rs", -"ui/issues/issue-19922.rs", -"ui/issues/issue-19982.rs", -"ui/issues/issue-19991.rs", -"ui/issues/issue-20009.rs", -"ui/issues/issue-20055-box-trait.rs", -"ui/issues/issue-20055-box-unsized-array.rs", -"ui/issues/issue-20162.rs", -"ui/issues/issue-20174.rs", -"ui/issues/issue-20186.rs", -"ui/issues/issue-20225.rs", -"ui/issues/issue-20261.rs", -"ui/issues/issue-20313-rpass.rs", -"ui/issues/issue-20313.rs", -"ui/issues/issue-20389.rs", -"ui/issues/issue-20396.rs", -"ui/issues/issue-20413.rs", -"ui/issues/issue-20414.rs", -"ui/issues/issue-20427.rs", -"ui/issues/issue-20433.rs", -"ui/issues/issue-20454.rs", -"ui/issues/issue-20544.rs", -"ui/issues/issue-20575.rs", -"ui/issues/issue-20644.rs", -"ui/issues/issue-20676.rs", -"ui/issues/issue-20714.rs", -"ui/issues/issue-2074.rs", -"ui/issues/issue-20763-1.rs", -"ui/issues/issue-20763-2.rs", -"ui/issues/issue-20772.rs", -"ui/issues/issue-20797.rs", -"ui/issues/issue-20803.rs", -"ui/issues/issue-20831-debruijn.rs", -"ui/issues/issue-20847.rs", -"ui/issues/issue-20939.rs", -"ui/issues/issue-20953.rs", -"ui/issues/issue-20971.rs", -"ui/issues/issue-21033.rs", -"ui/issues/issue-21140.rs", -"ui/issues/issue-21160.rs", -"ui/issues/issue-21174-2.rs", -"ui/issues/issue-21174.rs", -"ui/issues/issue-21177.rs", -"ui/issues/issue-21202.rs", -"ui/issues/issue-21245.rs", -"ui/issues/issue-21291.rs", -"ui/issues/issue-21306.rs", -"ui/issues/issue-21332.rs", -"ui/issues/issue-21361.rs", -"ui/issues/issue-21384.rs", -"ui/issues/issue-21400.rs", -"ui/issues/issue-21402.rs", -"ui/issues/issue-21449.rs", -"ui/issues/issue-2150.rs", -"ui/issues/issue-2151.rs", -"ui/issues/issue-21546.rs", -"ui/issues/issue-21554.rs", -"ui/issues/issue-21596.rs", -"ui/issues/issue-21600.rs", -"ui/issues/issue-21622.rs", -"ui/issues/issue-21634.rs", -"ui/issues/issue-21655.rs", -"ui/issues/issue-2170-exe.rs", -"ui/issues/issue-21701.rs", -"ui/issues/issue-21763.rs", -"ui/issues/issue-21891.rs", -"ui/issues/issue-2190-1.rs", -"ui/issues/issue-21909.rs", -"ui/issues/issue-21922.rs", -"ui/issues/issue-21946.rs", -"ui/issues/issue-21950.rs", -"ui/issues/issue-21974.rs", -"ui/issues/issue-22008.rs", -"ui/issues/issue-22034.rs", -"ui/issues/issue-22036.rs", -"ui/issues/issue-2214.rs", -"ui/issues/issue-22258.rs", -"ui/issues/issue-22289.rs", -"ui/issues/issue-22312.rs", -"ui/issues/issue-22346.rs", -"ui/issues/issue-22356.rs", -"ui/issues/issue-22370.rs", -"ui/issues/issue-22403.rs", -"ui/issues/issue-22426.rs", -"ui/issues/issue-22434.rs", -"ui/issues/issue-22468.rs", -"ui/issues/issue-22471.rs", -"ui/issues/issue-22577.rs", -"ui/issues/issue-22599.rs", -"ui/issues/issue-22603.rs", -"ui/issues/issue-22629.rs", -"ui/issues/issue-22638.rs", -"ui/issues/issue-22644.rs", -"ui/issues/issue-22673.rs", -"ui/issues/issue-22684.rs", -"ui/issues/issue-22706.rs", -"ui/issues/issue-22777.rs", -"ui/issues/issue-22781.rs", -"ui/issues/issue-22789.rs", -"ui/issues/issue-2281-part1.rs", -"ui/issues/issue-22814.rs", -"ui/issues/issue-2284.rs", -"ui/issues/issue-22864-1.rs", -"ui/issues/issue-22864-2.rs", -"ui/issues/issue-22872.rs", -"ui/issues/issue-22874.rs", -"ui/issues/issue-2288.rs", -"ui/issues/issue-22886.rs", -"ui/issues/issue-22894.rs", -"ui/issues/issue-22933-1.rs", -"ui/issues/issue-22933-2.rs", -"ui/issues/issue-22992-2.rs", -"ui/issues/issue-22992.rs", -"ui/issues/issue-23024.rs", -"ui/issues/issue-23036.rs", -"ui/issues/issue-23041.rs", -"ui/issues/issue-23046.rs", -"ui/issues/issue-23073.rs", -"ui/issues/issue-2311-2.rs", -"ui/issues/issue-2311.rs", -"ui/issues/issue-2312.rs", -"ui/issues/issue-23122-1.rs", -"ui/issues/issue-23122-2.rs", -"ui/issues/issue-2316-c.rs", -"ui/issues/issue-23173.rs", -"ui/issues/issue-23189.rs", -"ui/issues/issue-23217.rs", -"ui/issues/issue-23253.rs", -"ui/issues/issue-23261.rs", -"ui/issues/issue-23281.rs", -"ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs", -"ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs", -"ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs", -"ui/issues/issue-23304-1.rs", -"ui/issues/issue-23304-2.rs", -"ui/issues/issue-23311.rs", -"ui/issues/issue-23336.rs", -"ui/issues/issue-23354-2.rs", -"ui/issues/issue-23354.rs", -"ui/issues/issue-23406.rs", -"ui/issues/issue-23433.rs", -"ui/issues/issue-23442.rs", -"ui/issues/issue-23477.rs", -"ui/issues/issue-23485.rs", -"ui/issues/issue-23491.rs", -"ui/issues/issue-23543.rs", -"ui/issues/issue-23544.rs", -"ui/issues/issue-23550.rs", -"ui/issues/issue-23589.rs", -"ui/issues/issue-23649-1.rs", -"ui/issues/issue-23649-2.rs", -"ui/issues/issue-23649-3.rs", -"ui/issues/issue-23699.rs", -"ui/issues/issue-2380-b.rs", -"ui/issues/issue-23808.rs", -"ui/issues/issue-2383.rs", -"ui/issues/issue-23891.rs", -"ui/issues/issue-23898.rs", -"ui/issues/issue-23958.rs", -"ui/issues/issue-23966.rs", -"ui/issues/issue-23992.rs", -"ui/issues/issue-24013.rs", -"ui/issues/issue-24036.rs", -"ui/issues/issue-24086.rs", -"ui/issues/issue-2414-c.rs", -"ui/issues/issue-24161.rs", -"ui/issues/issue-24227.rs", -"ui/issues/issue-2428.rs", -"ui/issues/issue-24308.rs", -"ui/issues/issue-24322.rs", -"ui/issues/issue-24352.rs", -"ui/issues/issue-24353.rs", -"ui/issues/issue-24357.rs", -"ui/issues/issue-24363.rs", -"ui/issues/issue-24365.rs", -"ui/issues/issue-24389.rs", -"ui/issues/issue-24424.rs", -"ui/issues/issue-24434.rs", -"ui/issues/issue-2445-b.rs", -"ui/issues/issue-2445.rs", -"ui/issues/issue-24533.rs", -"ui/issues/issue-24589.rs", -"ui/issues/issue-2463.rs", -"ui/issues/issue-24682.rs", -"ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs", -"ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs", -"ui/issues/issue-2470-bounds-check-overflow.rs", -"ui/issues/issue-2472.rs", -"ui/issues/issue-24779.rs", -"ui/issues/issue-24819.rs", -"ui/issues/issue-2487-a.rs", -"ui/issues/issue-24945-repeat-dash-opts.rs", -"ui/issues/issue-24947.rs", -"ui/issues/issue-24954.rs", -"ui/issues/issue-2502.rs", -"ui/issues/issue-25076.rs", -"ui/issues/issue-25089.rs", -"ui/issues/issue-25145.rs", -"ui/issues/issue-25180.rs", -"ui/issues/issue-25185.rs", -"ui/issues/issue-2526-a.rs", -"ui/issues/issue-25279.rs", -"ui/issues/issue-25343.rs", -"ui/issues/issue-25368.rs", -"ui/issues/issue-25386.rs", -"ui/issues/issue-25394.rs", -"ui/issues/issue-25467.rs", -"ui/issues/issue-25497.rs", -"ui/issues/issue-2550.rs", -"ui/issues/issue-25515.rs", -"ui/issues/issue-25549-multiple-drop.rs", -"ui/issues/issue-25579.rs", -"ui/issues/issue-25679.rs", -"ui/issues/issue-25693.rs", -"ui/issues/issue-25746-bool-transmute.rs", -"ui/issues/issue-25757.rs", -"ui/issues/issue-25810.rs", -"ui/issues/issue-2590.rs", -"ui/issues/issue-25901.rs", -"ui/issues/issue-26056.rs", -"ui/issues/issue-26093.rs", -"ui/issues/issue-26095.rs", -"ui/issues/issue-2611-3.rs", -"ui/issues/issue-26127.rs", -"ui/issues/issue-26186.rs", -"ui/issues/issue-26205.rs", -"ui/issues/issue-26217.rs", -"ui/issues/issue-26237.rs", -"ui/issues/issue-2631-b.rs", -"ui/issues/issue-2642.rs", -"ui/issues/issue-26468.rs", -"ui/issues/issue-26472.rs", -"ui/issues/issue-26484.rs", -"ui/issues/issue-26614.rs", -"ui/issues/issue-26619.rs", -"ui/issues/issue-26641.rs", -"ui/issues/issue-26646.rs", -"ui/issues/issue-26655.rs", -"ui/issues/issue-26709.rs", -"ui/issues/issue-26802.rs", -"ui/issues/issue-26805.rs", -"ui/issues/issue-26812.rs", -"ui/issues/issue-26948.rs", -"ui/issues/issue-26997.rs", -"ui/issues/issue-27008.rs", -"ui/issues/issue-27033.rs", -"ui/issues/issue-27042.rs", -"ui/issues/issue-27054-primitive-binary-ops.rs", -"ui/issues/issue-27078.rs", -"ui/issues/issue-2708.rs", -"ui/issues/issue-27105.rs", -"ui/issues/issue-2723-b.rs", -"ui/issues/issue-27240.rs", -"ui/issues/issue-27268.rs", -"ui/issues/issue-27281.rs", -"ui/issues/issue-27340.rs", -"ui/issues/issue-27401-dropflag-reinit.rs", -"ui/issues/issue-27433.rs", -"ui/issues/issue-27592.rs", -"ui/issues/issue-2761.rs", -"ui/issues/issue-27639.rs", -"ui/issues/issue-27697.rs", -"ui/issues/issue-27815.rs", -"ui/issues/issue-27842.rs", -"ui/issues/issue-27889.rs", -"ui/issues/issue-27942.rs", -"ui/issues/issue-27949.rs", -"ui/issues/issue-27997.rs", -"ui/issues/issue-28105.rs", -"ui/issues/issue-28109.rs", -"ui/issues/issue-28181.rs", -"ui/issues/issue-2823.rs", -"ui/issues/issue-28279.rs", -"ui/issues/issue-28344.rs", -"ui/issues/issue-28433.rs", -"ui/issues/issue-28472.rs", -"ui/issues/issue-2848.rs", -"ui/issues/issue-2849.rs", -"ui/issues/issue-28498-must-work-ex1.rs", -"ui/issues/issue-28498-must-work-ex2.rs", -"ui/issues/issue-28498-ugeh-ex1.rs", -"ui/issues/issue-28550.rs", -"ui/issues/issue-28561.rs", -"ui/issues/issue-28568.rs", -"ui/issues/issue-28586.rs", -"ui/issues/issue-28600.rs", -"ui/issues/issue-28625.rs", -"ui/issues/issue-28776.rs", -"ui/issues/issue-28777.rs", -"ui/issues/issue-28828.rs", -"ui/issues/issue-28839.rs", -"ui/issues/issue-28936.rs", -"ui/issues/issue-2895.rs", -"ui/issues/issue-28971.rs", -"ui/issues/issue-28983.rs", -"ui/issues/issue-28999.rs", -"ui/issues/issue-29030.rs", -"ui/issues/issue-29037.rs", -"ui/issues/issue-2904.rs", -"ui/issues/issue-29048.rs", -"ui/issues/issue-29053.rs", -"ui/issues/issue-29071-2.rs", -"ui/issues/issue-29071.rs", -"ui/issues/issue-29092.rs", -"ui/issues/issue-29147-rpass.rs", -"ui/issues/issue-29147.rs", -"ui/issues/issue-29265.rs", -"ui/issues/issue-29276.rs", -"ui/issues/issue-2935.rs", -"ui/issues/issue-29466.rs", -"ui/issues/issue-29485.rs", -"ui/issues/issue-2951.rs", -"ui/issues/issue-29516.rs", -"ui/issues/issue-29522.rs", -"ui/issues/issue-29540.rs", -"ui/issues/issue-29663.rs", -"ui/issues/issue-29668.rs", -"ui/issues/issue-29710.rs", -"ui/issues/issue-29723.rs", -"ui/issues/issue-29740.rs", -"ui/issues/issue-29743.rs", -"ui/issues/issue-29821.rs", -"ui/issues/issue-29857.rs", -"ui/issues/issue-29861.rs", -"ui/issues/issue-2989.rs", -"ui/issues/issue-29948.rs", -"ui/issues/issue-2995.rs", -"ui/issues/issue-30018-panic.rs", -"ui/issues/issue-30081.rs", -"ui/issues/issue-3012-2.rs", -"ui/issues/issue-30123.rs", -"ui/issues/issue-3021-b.rs", -"ui/issues/issue-3021-d.rs", -"ui/issues/issue-30236.rs", -"ui/issues/issue-30255.rs", -"ui/issues/issue-3026.rs", -"ui/issues/issue-3029.rs", -"ui/issues/issue-3037.rs", -"ui/issues/issue-30371.rs", -"ui/issues/issue-3038.rs", -"ui/issues/issue-30380.rs", -"ui/issues/issue-3052.rs", -"ui/issues/issue-30530.rs", -"ui/issues/issue-30589.rs", -"ui/issues/issue-30615.rs", -"ui/issues/issue-30756.rs", -"ui/issues/issue-30891.rs", -"ui/issues/issue-3091.rs", -"ui/issues/issue-31011.rs", -"ui/issues/issue-3109.rs", -"ui/issues/issue-3121.rs", -"ui/issues/issue-31260.rs", -"ui/issues/issue-31267-additional.rs", -"ui/issues/issue-31267.rs", -"ui/issues/issue-31299.rs", -"ui/issues/issue-3136-b.rs", -"ui/issues/issue-3149.rs", -"ui/issues/issue-31511.rs", -"ui/issues/issue-3154.rs", -"ui/issues/issue-31702.rs", -"ui/issues/issue-31769.rs", -"ui/issues/issue-31776.rs", -"ui/issues/issue-31910.rs", -"ui/issues/issue-32004.rs", -"ui/issues/issue-32008.rs", -"ui/issues/issue-32086.rs", -"ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.rs", -"ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.rs", -"ui/issues/issue-3214.rs", -"ui/issues/issue-3220.rs", -"ui/issues/issue-32292.rs", -"ui/issues/issue-32324.rs", -"ui/issues/issue-32326.rs", -"ui/issues/issue-32377.rs", -"ui/issues/issue-32389.rs", -"ui/issues/issue-32518.rs", -"ui/issues/issue-32655.rs", -"ui/issues/issue-32782.rs", -"ui/issues/issue-32797.rs", -"ui/issues/issue-32805.rs", -"ui/issues/issue-3290.rs", -"ui/issues/issue-32950.rs", -"ui/issues/issue-32995-2.rs", -"ui/issues/issue-32995.rs", -"ui/issues/issue-33202.rs", -"ui/issues/issue-33241.rs", -"ui/issues/issue-33287.rs", -"ui/issues/issue-33293.rs", -"ui/issues/issue-33387.rs", -"ui/issues/issue-3344.rs", -"ui/issues/issue-33461.rs", -"ui/issues/issue-33504.rs", -"ui/issues/issue-33525.rs", -"ui/issues/issue-33571.rs", -"ui/issues/issue-33687.rs", -"ui/issues/issue-33770.rs", -"ui/issues/issue-3389.rs", -"ui/issues/issue-33941.rs", -"ui/issues/issue-33992.rs", -"ui/issues/issue-34047.rs", -"ui/issues/issue-34074.rs", -"ui/issues/issue-34209.rs", -"ui/issues/issue-34229.rs", -"ui/issues/issue-3424.rs", -"ui/issues/issue-3429.rs", -"ui/issues/issue-34334.rs", -"ui/issues/issue-34349.rs", -"ui/issues/issue-34373.rs", -"ui/issues/issue-34418.rs", -"ui/issues/issue-34427.rs", -"ui/issues/issue-3447.rs", -"ui/issues/issue-34503.rs", -"ui/issues/issue-34569.rs", -"ui/issues/issue-34571.rs", -"ui/issues/issue-34751.rs", -"ui/issues/issue-3477.rs", -"ui/issues/issue-34780.rs", -"ui/issues/issue-34796.rs", -"ui/issues/issue-34839.rs", -"ui/issues/issue-3500.rs", -"ui/issues/issue-35139.rs", -"ui/issues/issue-3521-2.rs", -"ui/issues/issue-35241.rs", -"ui/issues/issue-35423.rs", -"ui/issues/issue-3556.rs", -"ui/issues/issue-35570.rs", -"ui/issues/issue-3559.rs", -"ui/issues/issue-35600.rs", -"ui/issues/issue-3574.rs", -"ui/issues/issue-35815.rs", -"ui/issues/issue-35976.rs", -"ui/issues/issue-35988.rs", -"ui/issues/issue-36023.rs", -"ui/issues/issue-36036-associated-type-layout.rs", -"ui/issues/issue-36075.rs", -"ui/issues/issue-3609.rs", -"ui/issues/issue-36116.rs", -"ui/issues/issue-36260.rs", -"ui/issues/issue-36278-prefix-nesting.rs", -"ui/issues/issue-36299.rs", -"ui/issues/issue-36379.rs", -"ui/issues/issue-36400.rs", -"ui/issues/issue-36474.rs", -"ui/issues/issue-3656.rs", -"ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs", -"ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs", -"ui/issues/issue-36744-bitcast-args-if-needed.rs", -"ui/issues/issue-36786-resolve-call.rs", -"ui/issues/issue-3680.rs", -"ui/issues/issue-36816.rs", -"ui/issues/issue-36836.rs", -"ui/issues/issue-36839.rs", -"ui/issues/issue-36856.rs", -"ui/issues/issue-36936.rs", -"ui/issues/issue-36954.rs", -"ui/issues/issue-3702-2.rs", -"ui/issues/issue-3702.rs", -"ui/issues/issue-37051.rs", -"ui/issues/issue-37109.rs", -"ui/issues/issue-37131.rs", -"ui/issues/issue-37311-type-length-limit/issue-37311.rs", -"ui/issues/issue-37510.rs", -"ui/issues/issue-3753.rs", -"ui/issues/issue-37534.rs", -"ui/issues/issue-37576.rs", -"ui/issues/issue-3763.rs", -"ui/issues/issue-37665.rs", -"ui/issues/issue-37686.rs", -"ui/issues/issue-37725.rs", -"ui/issues/issue-37733.rs", -"ui/issues/issue-3779.rs", -"ui/issues/issue-37884.rs", -"ui/issues/issue-38160.rs", -"ui/issues/issue-38190.rs", -"ui/issues/issue-38226.rs", -"ui/issues/issue-38381.rs", -"ui/issues/issue-38412.rs", -"ui/issues/issue-38437.rs", -"ui/issues/issue-38458.rs", -"ui/issues/issue-3847.rs", -"ui/issues/issue-38556.rs", -"ui/issues/issue-38727.rs", -"ui/issues/issue-3874.rs", -"ui/issues/issue-38763.rs", -"ui/issues/issue-38857.rs", -"ui/issues/issue-38875/auxiliary/issue-38875-b.rs", -"ui/issues/issue-38875/issue-38875.rs", -"ui/issues/issue-3888-2.rs", -"ui/issues/issue-38919.rs", -"ui/issues/issue-38942.rs", -"ui/issues/issue-3895.rs", -"ui/issues/issue-38954.rs", -"ui/issues/issue-38987.rs", -"ui/issues/issue-39089.rs", -"ui/issues/issue-39175.rs", -"ui/issues/issue-39211.rs", -"ui/issues/issue-39367.rs", -"ui/issues/issue-39548.rs", -"ui/issues/issue-39687.rs", -"ui/issues/issue-39709.rs", -"ui/issues/issue-3979-2.rs", -"ui/issues/issue-3979-xcrate.rs", -"ui/issues/issue-3979.rs", -"ui/issues/issue-39808.rs", -"ui/issues/issue-39827.rs", -"ui/issues/issue-39848.rs", -"ui/issues/issue-3991.rs", -"ui/issues/issue-3993.rs", -"ui/issues/issue-39970.rs", -"ui/issues/issue-39984.rs", -"ui/issues/issue-40000.rs", -"ui/issues/issue-40136.rs", -"ui/issues/issue-40235.rs", -"ui/issues/issue-4025.rs", -"ui/issues/issue-40288-2.rs", -"ui/issues/issue-40288.rs", -"ui/issues/issue-40350.rs", -"ui/issues/issue-40402-ref-hints/issue-40402-1.rs", -"ui/issues/issue-40402-ref-hints/issue-40402-2.rs", -"ui/issues/issue-40408.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs", -"ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs", -"ui/issues/issue-40610.rs", -"ui/issues/issue-40749.rs", -"ui/issues/issue-40782.rs", -"ui/issues/issue-40827.rs", -"ui/issues/issue-40845.rs", -"ui/issues/issue-40861.rs", -"ui/issues/issue-40883.rs", -"ui/issues/issue-40951.rs", -"ui/issues/issue-41053.rs", -"ui/issues/issue-41139.rs", -"ui/issues/issue-41213.rs", -"ui/issues/issue-41229-ref-str.rs", -"ui/issues/issue-41272.rs", -"ui/issues/issue-41298.rs", -"ui/issues/issue-41479.rs", -"ui/issues/issue-41498.rs", -"ui/issues/issue-41549.rs", -"ui/issues/issue-41604.rs", -"ui/issues/issue-41628.rs", -"ui/issues/issue-41652/auxiliary/issue-41652-b.rs", -"ui/issues/issue-41652/issue-41652.rs", -"ui/issues/issue-41677.rs", -"ui/issues/issue-41696.rs", -"ui/issues/issue-41726.rs", -"ui/issues/issue-41742.rs", -"ui/issues/issue-41744.rs", -"ui/issues/issue-41849-variance-req.rs", -"ui/issues/issue-41880.rs", -"ui/issues/issue-41888.rs", -"ui/issues/issue-41936-variance-coerce-unsized-cycle.rs", -"ui/issues/issue-41974.rs", -"ui/issues/issue-41998.rs", -"ui/issues/issue-42007.rs", -"ui/issues/issue-4208.rs", -"ui/issues/issue-42106.rs", -"ui/issues/issue-42148.rs", -"ui/issues/issue-42210.rs", -"ui/issues/issue-4228.rs", -"ui/issues/issue-42312.rs", -"ui/issues/issue-42453.rs", -"ui/issues/issue-42467.rs", -"ui/issues/issue-4252.rs", -"ui/issues/issue-42552.rs", -"ui/issues/issue-4265.rs", -"ui/issues/issue-42755.rs", -"ui/issues/issue-42796.rs", -"ui/issues/issue-42880.rs", -"ui/issues/issue-42956.rs", -"ui/issues/issue-43057.rs", -"ui/issues/issue-43205.rs", -"ui/issues/issue-43250.rs", -"ui/issues/issue-43291.rs", -"ui/issues/issue-4333.rs", -"ui/issues/issue-4335.rs", -"ui/issues/issue-43355.rs", -"ui/issues/issue-43357.rs", -"ui/issues/issue-43420-no-over-suggest.rs", -"ui/issues/issue-43424.rs", -"ui/issues/issue-43431.rs", -"ui/issues/issue-43483.rs", -"ui/issues/issue-43692.rs", -"ui/issues/issue-43806.rs", -"ui/issues/issue-43853.rs", -"ui/issues/issue-4387.rs", -"ui/issues/issue-43910.rs", -"ui/issues/issue-43923.rs", -"ui/issues/issue-43925.rs", -"ui/issues/issue-43926.rs", -"ui/issues/issue-43988.rs", -"ui/issues/issue-44023.rs", -"ui/issues/issue-44056.rs", -"ui/issues/issue-44078.rs", -"ui/issues/issue-44216-add-instant.rs", -"ui/issues/issue-44216-add-system-time.rs", -"ui/issues/issue-44216-sub-instant.rs", -"ui/issues/issue-44216-sub-system-time.rs", -"ui/issues/issue-44239.rs", -"ui/issues/issue-44247.rs", -"ui/issues/issue-44405.rs", -"ui/issues/issue-4464.rs", -"ui/issues/issue-44730.rs", -"ui/issues/issue-44851.rs", -"ui/issues/issue-4517.rs", -"ui/issues/issue-4541.rs", -"ui/issues/issue-4542.rs", -"ui/issues/issue-45425.rs", -"ui/issues/issue-4545.rs", -"ui/issues/issue-45510.rs", -"ui/issues/issue-45562.rs", -"ui/issues/issue-45697-1.rs", -"ui/issues/issue-45697.rs", -"ui/issues/issue-45730.rs", -"ui/issues/issue-45731.rs", -"ui/issues/issue-45801.rs", -"ui/issues/issue-45965.rs", -"ui/issues/issue-46069.rs", -"ui/issues/issue-46101.rs", -"ui/issues/issue-46302.rs", -"ui/issues/issue-46311.rs", -"ui/issues/issue-46332.rs", -"ui/issues/issue-46471-1.rs", -"ui/issues/issue-46472.rs", -"ui/issues/issue-46604.rs", -"ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.rs", -"ui/issues/issue-46771.rs", -"ui/issues/issue-46855.rs", -"ui/issues/issue-46964.rs", -"ui/issues/issue-46983.rs", -"ui/issues/issue-47073-zero-padded-tuple-struct-indices.rs", -"ui/issues/issue-47094.rs", -"ui/issues/issue-47184.rs", -"ui/issues/issue-47309.rs", -"ui/issues/issue-4734.rs", -"ui/issues/issue-4735.rs", -"ui/issues/issue-4736.rs", -"ui/issues/issue-47364.rs", -"ui/issues/issue-47377.rs", -"ui/issues/issue-47380.rs", -"ui/issues/issue-47486.rs", -"ui/issues/issue-4759-1.rs", -"ui/issues/issue-4759.rs", -"ui/issues/issue-47638.rs", -"ui/issues/issue-47673.rs", -"ui/issues/issue-47703-1.rs", -"ui/issues/issue-47703-tuple.rs", -"ui/issues/issue-47703.rs", -"ui/issues/issue-47715.rs", -"ui/issues/issue-47722.rs", -"ui/issues/issue-48006.rs", -"ui/issues/issue-48131.rs", -"ui/issues/issue-48132.rs", -"ui/issues/issue-48159.rs", -"ui/issues/issue-48276.rs", -"ui/issues/issue-4830.rs", -"ui/issues/issue-48364.rs", -"ui/issues/issue-48728.rs", -"ui/issues/issue-4875.rs", -"ui/issues/issue-48838.rs", -"ui/issues/issue-48984.rs", -"ui/issues/issue-49298.rs", -"ui/issues/issue-4935.rs", -"ui/issues/issue-49544.rs", -"ui/issues/issue-49632.rs", -"ui/issues/issue-4968.rs", -"ui/issues/issue-4972.rs", -"ui/issues/issue-49824.rs", -"ui/issues/issue-49854.rs", -"ui/issues/issue-49919.rs", -"ui/issues/issue-49934-errors.rs", -"ui/issues/issue-49934.rs", -"ui/issues/issue-49955.rs", -"ui/issues/issue-49973.rs", -"ui/issues/issue-50187.rs", -"ui/issues/issue-50403.rs", -"ui/issues/issue-50411.rs", -"ui/issues/issue-50415.rs", -"ui/issues/issue-50442.rs", -"ui/issues/issue-50471.rs", -"ui/issues/issue-50518.rs", -"ui/issues/issue-50571.rs", -"ui/issues/issue-50581.rs", -"ui/issues/issue-50582.rs", -"ui/issues/issue-50585.rs", -"ui/issues/issue-50600.rs", -"ui/issues/issue-50618.rs", -"ui/issues/issue-5062.rs", -"ui/issues/issue-5067.rs", -"ui/issues/issue-50688.rs", -"ui/issues/issue-50714-1.rs", -"ui/issues/issue-50714.rs", -"ui/issues/issue-50761.rs", -"ui/issues/issue-50781.rs", -"ui/issues/issue-50802.rs", -"ui/issues/issue-50811.rs", -"ui/issues/issue-5100.rs", -"ui/issues/issue-51022.rs", -"ui/issues/issue-51044.rs", -"ui/issues/issue-51102.rs", -"ui/issues/issue-51116.rs", -"ui/issues/issue-51154.rs", -"ui/issues/issue-51515.rs", -"ui/issues/issue-51632-try-desugar-incompatible-types.rs", -"ui/issues/issue-51655.rs", -"ui/issues/issue-51714.rs", -"ui/issues/issue-51798.rs", -"ui/issues/issue-51874.rs", -"ui/issues/issue-51907.rs", -"ui/issues/issue-5192.rs", -"ui/issues/issue-51947.rs", -"ui/issues/issue-52049.rs", -"ui/issues/issue-52126-assign-op-invariance.rs", -"ui/issues/issue-52262.rs", -"ui/issues/issue-5239-1.rs", -"ui/issues/issue-5239-2.rs", -"ui/issues/issue-52489.rs", -"ui/issues/issue-52533.rs", -"ui/issues/issue-52717.rs", -"ui/issues/issue-5280.rs", -"ui/issues/issue-5315.rs", -"ui/issues/issue-5321-immediates-with-bare-self.rs", -"ui/issues/issue-53251.rs", -"ui/issues/issue-53275.rs", -"ui/issues/issue-53300.rs", -"ui/issues/issue-53333.rs", -"ui/issues/issue-53348.rs", -"ui/issues/issue-53419.rs", -"ui/issues/issue-53498.rs", -"ui/issues/issue-53568.rs", -"ui/issues/issue-5358-1.rs", -"ui/issues/issue-53728.rs", -"ui/issues/issue-53843.rs", -"ui/issues/issue-54044.rs", -"ui/issues/issue-54062.rs", -"ui/issues/issue-54094.rs", -"ui/issues/issue-5439.rs", -"ui/issues/issue-54410.rs", -"ui/issues/issue-54462-mutable-noalias-correctness.rs", -"ui/issues/issue-54477-reduced-2.rs", -"ui/issues/issue-54696.rs", -"ui/issues/issue-5518.rs", -"ui/issues/issue-5521.rs", -"ui/issues/issue-55376.rs", -"ui/issues/issue-55380.rs", -"ui/issues/issue-5550.rs", -"ui/issues/issue-5554.rs", -"ui/issues/issue-55587.rs", -"ui/issues/issue-5572.rs", -"ui/issues/issue-55731.rs", -"ui/issues/issue-56128.rs", -"ui/issues/issue-56175.rs", -"ui/issues/issue-56199.rs", -"ui/issues/issue-56229.rs", -"ui/issues/issue-56237.rs", -"ui/issues/issue-5666.rs", -"ui/issues/issue-56806.rs", -"ui/issues/issue-56835.rs", -"ui/issues/issue-56870.rs", -"ui/issues/issue-5688.rs", -"ui/issues/issue-56943.rs", -"ui/issues/issue-5708.rs", -"ui/issues/issue-57156.rs", -"ui/issues/issue-57162.rs", -"ui/issues/issue-5718.rs", -"ui/issues/issue-57198-pass.rs", -"ui/issues/issue-57271.rs", -"ui/issues/issue-57362-1.rs", -"ui/issues/issue-57362-2.rs", -"ui/issues/issue-57399-self-return-impl-trait.rs", -"ui/issues/issue-5741.rs", -"ui/issues/issue-5754.rs", -"ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs", -"ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs", -"ui/issues/issue-57781.rs", -"ui/issues/issue-57924.rs", -"ui/issues/issue-58212.rs", -"ui/issues/issue-58375-monomorphize-default-impls.rs", -"ui/issues/issue-5844.rs", -"ui/issues/issue-58463.rs", -"ui/issues/issue-58712.rs", -"ui/issues/issue-58734.rs", -"ui/issues/issue-5883.rs", -"ui/issues/issue-5884.rs", -"ui/issues/issue-58857.rs", -"ui/issues/issue-5900.rs", -"ui/issues/issue-59020.rs", -"ui/issues/issue-5917.rs", -"ui/issues/issue-59326.rs", -"ui/issues/issue-59488.rs", -"ui/issues/issue-59494.rs", -"ui/issues/issue-5950.rs", -"ui/issues/issue-59756.rs", -"ui/issues/issue-5988.rs", -"ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs", -"ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs", -"ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs", -"ui/issues/issue-60218.rs", -"ui/issues/issue-60622.rs", -"ui/issues/issue-60989.rs", -"ui/issues/issue-61106.rs", -"ui/issues/issue-61108.rs", -"ui/issues/issue-6117.rs", -"ui/issues/issue-6130.rs", -"ui/issues/issue-61475.rs", -"ui/issues/issue-6153.rs", -"ui/issues/issue-61623.rs", -"ui/issues/issue-61894.rs", -"ui/issues/issue-62480.rs", -"ui/issues/issue-6318.rs", -"ui/issues/issue-6344-let.rs", -"ui/issues/issue-6344-match.rs", -"ui/issues/issue-63983.rs", -"ui/issues/issue-64430.rs", -"ui/issues/issue-64559.rs", -"ui/issues/issue-64593.rs", -"ui/issues/issue-64792-bad-unicode-ctor.rs", -"ui/issues/issue-65131.rs", -"ui/issues/issue-65230.rs", -"ui/issues/issue-65462.rs", -"ui/issues/issue-6557.rs", -"ui/issues/issue-66308.rs", -"ui/issues/issue-66353.rs", -"ui/issues/issue-66667-function-cmp-cycle.rs", -"ui/issues/issue-66702-break-outside-loop-val.rs", -"ui/issues/issue-66706.rs", -"ui/issues/issue-66923-show-error-for-correct-call.rs", -"ui/issues/issue-67039-unsound-pin-partialeq.rs", -"ui/issues/issue-6738.rs", -"ui/issues/issue-67535.rs", -"ui/issues/issue-67552.rs", -"ui/issues/issue-68010-large-zst-consts.rs", -"ui/issues/issue-68696-catch-during-unwind.rs", -"ui/issues/issue-6892.rs", -"ui/issues/issue-68951.rs", -"ui/issues/issue-6898.rs", -"ui/issues/issue-69130.rs", -"ui/issues/issue-6919.rs", -"ui/issues/issue-69306.rs", -"ui/issues/issue-6936.rs", -"ui/issues/issue-69455.rs", -"ui/issues/issue-69602-type-err-during-codegen-ice.rs", -"ui/issues/issue-69683.rs", -"ui/issues/issue-70093/issue-70093-link-directives.rs", -"ui/issues/issue-70093/issue-70093.rs", -"ui/issues/issue-7012.rs", -"ui/issues/issue-70381.rs", -"ui/issues/issue-7044.rs", -"ui/issues/issue-7061.rs", -"ui/issues/issue-70673.rs", -"ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs", -"ui/issues/issue-70746.rs", -"ui/issues/issue-7092.rs", -"ui/issues/issue-71406.rs", -"ui/issues/issue-71676-suggest-deref/issue-71676-1.rs", -"ui/issues/issue-71676-suggest-deref/issue-71676-2.rs", -"ui/issues/issue-7178.rs", -"ui/issues/issue-72002.rs", -"ui/issues/issue-72076.rs", -"ui/issues/issue-72278.rs", -"ui/issues/issue-7246.rs", -"ui/issues/issue-7268.rs", -"ui/issues/issue-72839-error-overflow.rs", -"ui/issues/issue-72933-match-stack-overflow.rs", -"ui/issues/issue-73112.rs", -"ui/issues/issue-73229.rs", -"ui/issues/issue-7344.rs", -"ui/issues/issue-7364.rs", -"ui/issues/issue-74082.rs", -"ui/issues/issue-74564-if-expr-stack-overflow.rs", -"ui/issues/issue-7519-match-unit-in-arg.rs", -"ui/issues/issue-75283.rs", -"ui/issues/issue-7563.rs", -"ui/issues/issue-75704.rs", -"ui/issues/issue-7575.rs", -"ui/issues/issue-76042.rs", -"ui/issues/issue-7607-1.rs", -"ui/issues/issue-7607-2.rs", -"ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs", -"ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs", -"ui/issues/issue-76191.rs", -"ui/issues/issue-7660.rs", -"ui/issues/issue-7663.rs", -"ui/issues/issue-7673-cast-generically-implemented-trait.rs", -"ui/issues/issue-77218/issue-77218-2.rs", -"ui/issues/issue-77218/issue-77218.rs", -"ui/issues/issue-7784.rs", -"ui/issues/issue-77919.rs", -"ui/issues/issue-78192.rs", -"ui/issues/issue-78622.rs", -"ui/issues/issue-7867.rs", -"ui/issues/issue-78957.rs", -"ui/issues/issue-7899.rs", -"ui/issues/issue-7911.rs", -"ui/issues/issue-7970a.rs", -"ui/issues/issue-8044.rs", -"ui/issues/issue-80607.rs", -"ui/issues/issue-81584.rs", -"ui/issues/issue-8171-default-method-self-inherit-builtin-trait.rs", -"ui/issues/issue-81918.rs", -"ui/issues/issue-8248.rs", -"ui/issues/issue-8249.rs", -"ui/issues/issue-8259.rs", -"ui/issues/issue-83048.rs", -"ui/issues/issue-8391.rs", -"ui/issues/issue-8398.rs", -"ui/issues/issue-8401.rs", -"ui/issues/issue-8498.rs", -"ui/issues/issue-8506.rs", -"ui/issues/issue-8521.rs", -"ui/issues/issue-85461.rs", -"ui/issues/issue-8578.rs", -"ui/issues/issue-86756.rs", -"ui/issues/issue-87199.rs", -"ui/issues/issue-8727.rs", -"ui/issues/issue-87490.rs", -"ui/issues/issue-8761.rs", -"ui/issues/issue-8767.rs", -"ui/issues/issue-87707.rs", -"ui/issues/issue-8783.rs", -"ui/issues/issue-88150.rs", -"ui/issues/issue-8860.rs", -"ui/issues/issue-8898.rs", -"ui/issues/issue-9047.rs", -"ui/issues/issue-9110.rs", -"ui/issues/issue-9123.rs", -"ui/issues/issue-9129.rs", -"ui/issues/issue-91489.rs", -"ui/issues/issue-9155.rs", -"ui/issues/issue-9188.rs", -"ui/issues/issue-9243.rs", -"ui/issues/issue-9249.rs", -"ui/issues/issue-9259.rs", -"ui/issues/issue-92741.rs", -"ui/issues/issue-9382.rs", -"ui/issues/issue-9446.rs", -"ui/issues/issue-9575.rs", -"ui/issues/issue-9719.rs", -"ui/issues/issue-9725.rs", -"ui/issues/issue-9737.rs", -"ui/issues/issue-9814.rs", -"ui/issues/issue-98299.rs", -"ui/issues/issue-9837.rs", -"ui/issues/issue-9906.rs", -"ui/issues/issue-9918.rs", -"ui/issues/issue-9942.rs", -"ui/issues/issue-9951.rs", -"ui/issues/issue-9968.rs", -"ui/issues/issue-99838.rs", -"ui/iterators/issue-28098.rs", -"ui/iterators/issue-58952-filter-type-length.rs", -"ui/lang-items/issue-19660.rs", -"ui/lang-items/issue-83471.rs", -"ui/lang-items/issue-87573.rs", -"ui/late-bound-lifetimes/issue-36381.rs", -"ui/late-bound-lifetimes/issue-47511.rs", -"ui/late-bound-lifetimes/issue-80618.rs", -"ui/layout/issue-112048-unsizing-field-order.rs", -"ui/layout/issue-112048-unsizing-niche.rs", -"ui/layout/issue-113941.rs", -"ui/layout/issue-60431-unsized-tail-behind-projection.rs", -"ui/layout/issue-84108.rs", -"ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs", -"ui/layout/issue-96185-overaligned-enum.rs", -"ui/let-else/issue-100103.rs", -"ui/let-else/issue-102317.rs", -"ui/let-else/issue-94176.rs", -"ui/let-else/issue-99975.rs", -"ui/lifetimes/auxiliary/issue-91763-aux.rs", -"ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs", -"ui/lifetimes/issue-104432-unused-lifetimes-in-expansion.rs", -"ui/lifetimes/issue-105227.rs", -"ui/lifetimes/issue-105507.rs", -"ui/lifetimes/issue-105675.rs", -"ui/lifetimes/issue-107492-default-value-for-lifetime.rs", -"ui/lifetimes/issue-107988.rs", -"ui/lifetimes/issue-17728.rs", -"ui/lifetimes/issue-19707.rs", -"ui/lifetimes/issue-26638.rs", -"ui/lifetimes/issue-34979.rs", -"ui/lifetimes/issue-36744-without-calls.rs", -"ui/lifetimes/issue-54378.rs", -"ui/lifetimes/issue-55796.rs", -"ui/lifetimes/issue-64173-unused-lifetimes.rs", -"ui/lifetimes/issue-67498.rs", -"ui/lifetimes/issue-69314.rs", -"ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs", -"ui/lifetimes/issue-76168-hr-outlives-2.rs", -"ui/lifetimes/issue-76168-hr-outlives-3.rs", -"ui/lifetimes/issue-76168-hr-outlives.rs", -"ui/lifetimes/issue-77175.rs", -"ui/lifetimes/issue-79187-2.rs", -"ui/lifetimes/issue-79187.rs", -"ui/lifetimes/issue-83737-binders-across-types.rs", -"ui/lifetimes/issue-83737-erasing-bound-vars.rs", -"ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs", -"ui/lifetimes/issue-83907-invalid-fn-like-path.rs", -"ui/lifetimes/issue-84398.rs", -"ui/lifetimes/issue-84604.rs", -"ui/lifetimes/issue-90170-elision-mismatch.rs", -"ui/lifetimes/issue-90600-expected-return-static-indirect.rs", -"ui/lifetimes/issue-91763.rs", -"ui/lifetimes/issue-93911.rs", -"ui/lifetimes/issue-95023.rs", -"ui/lifetimes/issue-97193.rs", -"ui/lifetimes/issue-97194.rs", -"ui/lifetimes/lifetime-errors/issue_74400.rs", -"ui/limits/issue-15919-32.rs", -"ui/limits/issue-15919-64.rs", -"ui/limits/issue-17913.rs", -"ui/limits/issue-55878.rs", -"ui/limits/issue-56762.rs", -"ui/limits/issue-69485-var-size-diffs-too-large.rs", -"ui/limits/issue-75158-64.rs", -"ui/linkage-attr/issue-10755.rs", -"ui/linkage-attr/issue-109144.rs", -"ui/lint/dead-code/issue-41883.rs", -"ui/lint/dead-code/issue-59003.rs", -"ui/lint/dead-code/issue-68408-false-positive.rs", -"ui/lint/dead-code/issue-85071-2.rs", -"ui/lint/dead-code/issue-85071.rs", -"ui/lint/dead-code/issue-85255.rs", -"ui/lint/issue-101284.rs", -"ui/lint/issue-102705.rs", -"ui/lint/issue-103317.rs", -"ui/lint/issue-103435-extra-parentheses.rs", -"ui/lint/issue-104392.rs", -"ui/lint/issue-104897.rs", -"ui/lint/issue-106991.rs", -"ui/lint/issue-108155.rs", -"ui/lint/issue-109152.rs", -"ui/lint/issue-109529.rs", -"ui/lint/issue-110573.rs", -"ui/lint/issue-111359.rs", -"ui/lint/issue-112489.rs", -"ui/lint/issue-117949.rs", -"ui/lint/issue-121070-let-range.rs", -"ui/lint/issue-14309.rs", -"ui/lint/issue-14837.rs", -"ui/lint/issue-17718-const-naming.rs", -"ui/lint/issue-1866.rs", -"ui/lint/issue-19102.rs", -"ui/lint/issue-20343.rs", -"ui/lint/issue-30302.rs", -"ui/lint/issue-31924-non-snake-ffi.rs", -"ui/lint/issue-34798.rs", -"ui/lint/issue-35075.rs", -"ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs", -"ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs", -"ui/lint/issue-54099-camel-case-underscore-types.rs", -"ui/lint/issue-57410-1.rs", -"ui/lint/issue-57410.rs", -"ui/lint/issue-63364.rs", -"ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs", -"ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs", -"ui/lint/issue-79546-fuel-ice.rs", -"ui/lint/issue-79744.rs", -"ui/lint/issue-80988.rs", -"ui/lint/issue-81218.rs", -"ui/lint/issue-83477.rs", -"ui/lint/issue-87274-paren-parent.rs", -"ui/lint/issue-89469.rs", -"ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs", -"ui/lint/issue-97094.rs", -"ui/lint/issue-99387.rs", -"ui/lint/let_underscore/issue-119696-err-on-fn.rs", -"ui/lint/let_underscore/issue-119697-extra-let.rs", -"ui/lint/must_not_suspend/issue-89562.rs", -"ui/lint/unused/issue-103320-must-use-ops.rs", -"ui/lint/unused/issue-104397.rs", -"ui/lint/unused/issue-105061-array-lint.rs", -"ui/lint/unused/issue-105061-should-lint.rs", -"ui/lint/unused/issue-105061.rs", -"ui/lint/unused/issue-117142-invalid-remove-parens.rs", -"ui/lint/unused/issue-117284-arg-in-macro.rs", -"ui/lint/unused/issue-119383-if-let-guard.rs", -"ui/lint/unused/issue-30730.rs", -"ui/lint/unused/issue-46576.rs", -"ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs", -"ui/lint/unused/issue-54180-unused-ref-field.rs", -"ui/lint/unused/issue-54538-unused-parens-lint.rs", -"ui/lint/unused/issue-59896.rs", -"ui/lint/unused/issue-67691-unused-field-in-or-pattern.rs", -"ui/lint/unused/issue-70041.rs", -"ui/lint/unused/issue-71290-unused-paren-binop.rs", -"ui/lint/unused/issue-74883-unused-paren-baren-yield.rs", -"ui/lint/unused/issue-81314-unused-span-ident.rs", -"ui/lint/unused/issue-85913.rs", -"ui/lint/unused/issue-88519-unused-paren.rs", -"ui/lint/unused/issue-90807-unused-paren-error.rs", -"ui/lint/unused/issue-90807-unused-paren.rs", -"ui/lint/unused/issue-92751.rs", -"ui/lint/unused/issue-96606.rs", -"ui/lint/use-redundant/issue-92904.rs", -"ui/loops/issue-1962.rs", -"ui/loops/issue-1974.rs", -"ui/loops/issue-43162.rs", -"ui/loops/issue-50576.rs", -"ui/loops/issue-69225-SCEVAddExpr-wrap-flag.rs", -"ui/loops/issue-69225-layout-repeated-checked-add.rs", -"ui/loops/issue-82916.rs", -"ui/lowering/issue-121108.rs", -"ui/lowering/issue-96847.rs", -"ui/lto/issue-100772.rs", -"ui/lto/issue-105637.rs", -"ui/lto/issue-11154.rs", -"ui/macros/auxiliary/issue-100199.rs", -"ui/macros/auxiliary/issue-19163.rs", -"ui/macros/auxiliary/issue-40469.rs", -"ui/macros/auxiliary/issue-75982.rs", -"ui/macros/issue-100199.rs", -"ui/macros/issue-102878.rs", -"ui/macros/issue-103529.rs", -"ui/macros/issue-104769-concat_bytes-invalid-literal.rs", -"ui/macros/issue-105011.rs", -"ui/macros/issue-10536.rs", -"ui/macros/issue-106837.rs", -"ui/macros/issue-109237.rs", -"ui/macros/issue-111749.rs", -"ui/macros/issue-112342-1.rs", -"ui/macros/issue-112342-2.rs", -"ui/macros/issue-118048.rs", -"ui/macros/issue-118786.rs", -"ui/macros/issue-16098.rs", -"ui/macros/issue-19163.rs", -"ui/macros/issue-21356.rs", -"ui/macros/issue-22463.rs", -"ui/macros/issue-25274.rs", -"ui/macros/issue-25385.rs", -"ui/macros/issue-26094.rs", -"ui/macros/issue-26322.rs", -"ui/macros/issue-2804-2.rs", -"ui/macros/issue-2804.rs", -"ui/macros/issue-29084.rs", -"ui/macros/issue-30007.rs", -"ui/macros/issue-30143.rs", -"ui/macros/issue-33185.rs", -"ui/macros/issue-34171.rs", -"ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs", -"ui/macros/issue-35450.rs", -"ui/macros/issue-37175.rs", -"ui/macros/issue-38715.rs", -"ui/macros/issue-39388.rs", -"ui/macros/issue-39404.rs", -"ui/macros/issue-39467.rs", -"ui/macros/issue-40469.rs", -"ui/macros/issue-40770.rs", -"ui/macros/issue-41776.rs", -"ui/macros/issue-41803.rs", -"ui/macros/issue-42954.rs", -"ui/macros/issue-44127.rs", -"ui/macros/issue-46438.rs", -"ui/macros/issue-5060.rs", -"ui/macros/issue-51848.rs", -"ui/macros/issue-52169.rs", -"ui/macros/issue-54441.rs", -"ui/macros/issue-57597.rs", -"ui/macros/issue-58490.rs", -"ui/macros/issue-61033-1.rs", -"ui/macros/issue-61033-2.rs", -"ui/macros/issue-61053-different-kleene.rs", -"ui/macros/issue-61053-duplicate-binder.rs", -"ui/macros/issue-61053-missing-repetition.rs", -"ui/macros/issue-61053-unbound.rs", -"ui/macros/issue-63102.rs", -"ui/macros/issue-6596-1.rs", -"ui/macros/issue-6596-2.rs", -"ui/macros/issue-68058.rs", -"ui/macros/issue-68060.rs", -"ui/macros/issue-69396-const-no-type-in-macro.rs", -"ui/macros/issue-69838-mods-relative-to-included-path.rs", -"ui/macros/issue-70446.rs", -"ui/macros/issue-75982-foreign-macro-weird-mod.rs", -"ui/macros/issue-77475.rs", -"ui/macros/issue-78325-inconsistent-resolution.rs", -"ui/macros/issue-78333.rs", -"ui/macros/issue-78892-substitution-in-statement-attr.rs", -"ui/macros/issue-81006.rs", -"ui/macros/issue-83340.rs", -"ui/macros/issue-83344.rs", -"ui/macros/issue-84195-lint-anon-const.rs", -"ui/macros/issue-84429-matches-edition.rs", -"ui/macros/issue-84632-eager-expansion-recursion-limit.rs", -"ui/macros/issue-86082-option-env-invalid-char.rs", -"ui/macros/issue-86865.rs", -"ui/macros/issue-8709.rs", -"ui/macros/issue-87877.rs", -"ui/macros/issue-88206.rs", -"ui/macros/issue-88228.rs", -"ui/macros/issue-8851.rs", -"ui/macros/issue-92267.rs", -"ui/macros/issue-95267.rs", -"ui/macros/issue-95533.rs", -"ui/macros/issue-98466-allow.rs", -"ui/macros/issue-98466.rs", -"ui/macros/issue-98790.rs", -"ui/macros/issue-99261.rs", -"ui/macros/issue-99265.rs", -"ui/macros/issue-99907.rs", -"ui/macros/rfc-3086-metavar-expr/issue-111904.rs", -"ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs", -"ui/malformed/issue-69341-malformed-derive-inert.rs", -"ui/marker_trait_attr/issue-61651-type-mismatch.rs", -"ui/match/issue-112438.rs", -"ui/match/issue-113012.rs", -"ui/match/issue-11319.rs", -"ui/match/issue-114691.rs", -"ui/match/issue-115681.rs", -"ui/match/issue-11940.rs", -"ui/match/issue-12552.rs", -"ui/match/issue-18060.rs", -"ui/match/issue-26251.rs", -"ui/match/issue-26996.rs", -"ui/match/issue-27021.rs", -"ui/match/issue-33498.rs", -"ui/match/issue-36401.rs", -"ui/match/issue-37598.rs", -"ui/match/issue-42679.rs", -"ui/match/issue-46920-byte-array-patterns.rs", -"ui/match/issue-5530.rs", -"ui/match/issue-56685.rs", -"ui/match/issue-70972-dyn-trait.rs", -"ui/match/issue-72680.rs", -"ui/match/issue-72896-non-partial-eq-const.rs", -"ui/match/issue-74050-end-span.rs", -"ui/match/issue-82392.rs", -"ui/match/issue-82866.rs", -"ui/match/issue-84434.rs", -"ui/match/issue-91058.rs", -"ui/match/issue-92100.rs", -"ui/methods/issue-19521.rs", -"ui/methods/issue-3707.rs", -"ui/methods/issue-7950.rs", -"ui/methods/issues/issue-105732.rs", -"ui/methods/issues/issue-61525.rs", -"ui/methods/issues/issue-84495.rs", -"ui/methods/issues/issue-90315.rs", -"ui/methods/issues/issue-94581.rs", -"ui/mir/auxiliary/issue_76375_aux.rs", -"ui/mir/issue-101844.rs", -"ui/mir/issue-102389.rs", -"ui/mir/issue-105809.rs", -"ui/mir/issue-106062.rs", -"ui/mir/issue-107678-projection-with-lifetime.rs", -"ui/mir/issue-107691.rs", -"ui/mir/issue-109004-drop-large-array.rs", -"ui/mir/issue-109743.rs", -"ui/mir/issue-112269.rs", -"ui/mir/issue-121103.rs", -"ui/mir/issue-29227.rs", -"ui/mir/issue-46845.rs", -"ui/mir/issue-60390.rs", -"ui/mir/issue-66851.rs", -"ui/mir/issue-66930.rs", -"ui/mir/issue-67639-normalization-ice.rs", -"ui/mir/issue-67710-inline-projection.rs", -"ui/mir/issue-67947.rs", -"ui/mir/issue-68841.rs", -"ui/mir/issue-71793-inline-args-storage.rs", -"ui/mir/issue-73914.rs", -"ui/mir/issue-74739.rs", -"ui/mir/issue-75053.rs", -"ui/mir/issue-75419-validation-impl-trait.rs", -"ui/mir/issue-76248.rs", -"ui/mir/issue-76375.rs", -"ui/mir/issue-76740-copy-propagation.rs", -"ui/mir/issue-76803-branches-not-same.rs", -"ui/mir/issue-77002.rs", -"ui/mir/issue-77359-simplify-arm-identity.rs", -"ui/mir/issue-77911.rs", -"ui/mir/issue-78496.rs", -"ui/mir/issue-80949.rs", -"ui/mir/issue-83499-input-output-iteration-ice.rs", -"ui/mir/issue-89485.rs", -"ui/mir/issue-91745.rs", -"ui/mir/issue-92893.rs", -"ui/mir/issue-99852.rs", -"ui/mir/issue-99866.rs", -"ui/mir/issue66339.rs", -"ui/mir/validate/issue-95978-validator-lifetime-comparison.rs", -"ui/mismatched_types/issue-106182.rs", -"ui/mismatched_types/issue-112036.rs", -"ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs", -"ui/mismatched_types/issue-118510.rs", -"ui/mismatched_types/issue-13033.rs", -"ui/mismatched_types/issue-1362.rs", -"ui/mismatched_types/issue-1448-2.rs", -"ui/mismatched_types/issue-19109.rs", -"ui/mismatched_types/issue-26480.rs", -"ui/mismatched_types/issue-35030.rs", -"ui/mismatched_types/issue-36053-2.rs", -"ui/mismatched_types/issue-38371-unfixable.rs", -"ui/mismatched_types/issue-38371.rs", -"ui/mismatched_types/issue-47706-trait.rs", -"ui/mismatched_types/issue-47706.rs", -"ui/mismatched_types/issue-74918-missing-lifetime.rs", -"ui/mismatched_types/issue-75361-mismatched-impl.rs", -"ui/mismatched_types/issue-84976.rs", -"ui/missing-trait-bounds/auxiliary/issue-69725.rs", -"ui/missing-trait-bounds/issue-35677.rs", -"ui/missing-trait-bounds/issue-69725.rs", -"ui/modules/issue-107649.rs", -"ui/modules/issue-56411-aux.rs", -"ui/modules/issue-56411.rs", -"ui/moves/issue-22536-copy-mustnt-zero.rs", -"ui/moves/issue-34721.rs", -"ui/moves/issue-46099-move-in-macro.rs", -"ui/moves/issue-72649-uninit-in-loop.rs", -"ui/moves/issue-75904-move-closure-loop.rs", -"ui/moves/issue-99470-move-out-of-some.rs", -"ui/never_type/issue-10176.rs", -"ui/never_type/issue-13352.rs", -"ui/never_type/issue-2149.rs", -"ui/never_type/issue-44402.rs", -"ui/never_type/issue-51506.rs", -"ui/never_type/issue-52443.rs", -"ui/never_type/issue-5500-1.rs", -"ui/never_type/issue-96335.rs", -"ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs", -"ui/nll/issue-112604-closure-output-normalize.rs", -"ui/nll/issue-16223.rs", -"ui/nll/issue-21114-ebfull.rs", -"ui/nll/issue-21114-kixunil.rs", -"ui/nll/issue-21232-partial-init-and-erroneous-use.rs", -"ui/nll/issue-21232-partial-init-and-use.rs", -"ui/nll/issue-22323-temp-destruction.rs", -"ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs", -"ui/nll/issue-27282-move-match-input-into-guard.rs", -"ui/nll/issue-27282-move-ref-mut-into-guard.rs", -"ui/nll/issue-27282-mutate-before-diverging-arm-1.rs", -"ui/nll/issue-27282-mutate-before-diverging-arm-2.rs", -"ui/nll/issue-27282-mutate-before-diverging-arm-3.rs", -"ui/nll/issue-27282-mutation-in-guard.rs", -"ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs", -"ui/nll/issue-27583.rs", -"ui/nll/issue-27868.rs", -"ui/nll/issue-30104.rs", -"ui/nll/issue-30438-a.rs", -"ui/nll/issue-30438-b.rs", -"ui/nll/issue-30438-c.rs", -"ui/nll/issue-31567.rs", -"ui/nll/issue-32382-index-assoc-type-with-lifetime.rs", -"ui/nll/issue-42574-diagnostic-in-nested-closure.rs", -"ui/nll/issue-43058.rs", -"ui/nll/issue-45157.rs", -"ui/nll/issue-45696-long-live-borrows-in-boxes.rs", -"ui/nll/issue-45696-no-variant-box-recur.rs", -"ui/nll/issue-45696-scribble-on-boxed-borrow.rs", -"ui/nll/issue-46023.rs", -"ui/nll/issue-46036.rs", -"ui/nll/issue-46589.rs", -"ui/nll/issue-47022.rs", -"ui/nll/issue-47153-generic-const.rs", -"ui/nll/issue-47388.rs", -"ui/nll/issue-47470.rs", -"ui/nll/issue-47589.rs", -"ui/nll/issue-48070.rs", -"ui/nll/issue-48179.rs", -"ui/nll/issue-48238.rs", -"ui/nll/issue-48623-closure.rs", -"ui/nll/issue-48623-coroutine.rs", -"ui/nll/issue-48697.rs", -"ui/nll/issue-48803.rs", -"ui/nll/issue-50343.rs", -"ui/nll/issue-50461-used-mut-from-moves.rs", -"ui/nll/issue-50716-1.rs", -"ui/nll/issue-50716.rs", -"ui/nll/issue-51191.rs", -"ui/nll/issue-51244.rs", -"ui/nll/issue-51268.rs", -"ui/nll/issue-51345-2.rs", -"ui/nll/issue-51351.rs", -"ui/nll/issue-51512.rs", -"ui/nll/issue-51770.rs", -"ui/nll/issue-52057.rs", -"ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs", -"ui/nll/issue-52078.rs", -"ui/nll/issue-52086.rs", -"ui/nll/issue-52113.rs", -"ui/nll/issue-52213.rs", -"ui/nll/issue-52533-1.rs", -"ui/nll/issue-52534-1.rs", -"ui/nll/issue-52534-2.rs", -"ui/nll/issue-52534.rs", -"ui/nll/issue-52663-span-decl-captured-variable.rs", -"ui/nll/issue-52663-trait-object.rs", -"ui/nll/issue-52669.rs", -"ui/nll/issue-52742.rs", -"ui/nll/issue-52992.rs", -"ui/nll/issue-53040.rs", -"ui/nll/issue-53119.rs", -"ui/nll/issue-53123-raw-pointer-cast.rs", -"ui/nll/issue-53570.rs", -"ui/nll/issue-53773.rs", -"ui/nll/issue-53807.rs", -"ui/nll/issue-54189.rs", -"ui/nll/issue-54302-cases.rs", -"ui/nll/issue-54302.rs", -"ui/nll/issue-54382-use-span-of-tail-of-block.rs", -"ui/nll/issue-54556-niconii.rs", -"ui/nll/issue-54556-stephaneyfx.rs", -"ui/nll/issue-54556-temps-in-tail-diagnostic.rs", -"ui/nll/issue-54556-used-vs-unused-tails.rs", -"ui/nll/issue-54556-wrap-it-up.rs", -"ui/nll/issue-54779-anon-static-lifetime.rs", -"ui/nll/issue-54943-3.rs", -"ui/nll/issue-54943.rs", -"ui/nll/issue-55288.rs", -"ui/nll/issue-55344.rs", -"ui/nll/issue-55394.rs", -"ui/nll/issue-55401.rs", -"ui/nll/issue-55511.rs", -"ui/nll/issue-55651.rs", -"ui/nll/issue-55825-const-fn.rs", -"ui/nll/issue-55850.rs", -"ui/nll/issue-57100.rs", -"ui/nll/issue-57265-return-type-wf-check.rs", -"ui/nll/issue-57280-1-flipped.rs", -"ui/nll/issue-57280-1.rs", -"ui/nll/issue-57280.rs", -"ui/nll/issue-57642-higher-ranked-subtype.rs", -"ui/nll/issue-57843.rs", -"ui/nll/issue-57960.rs", -"ui/nll/issue-57989.rs", -"ui/nll/issue-58053.rs", -"ui/nll/issue-58299.rs", -"ui/nll/issue-61311-normalize.rs", -"ui/nll/issue-61320-normalize.rs", -"ui/nll/issue-61424.rs", -"ui/nll/issue-62007-assign-const-index.rs", -"ui/nll/issue-62007-assign-differing-fields.rs", -"ui/nll/issue-63154-normalize.rs", -"ui/nll/issue-67007-escaping-data.rs", -"ui/nll/issue-68550.rs", -"ui/nll/issue-69114-static-mut-ty.rs", -"ui/nll/issue-69114-static-ty.rs", -"ui/nll/issue-73159-rpit-static.rs", -"ui/nll/issue-75777.rs", -"ui/nll/issue-78561.rs", -"ui/nll/issue-95272.rs", -"ui/nll/issue-97997.rs", -"ui/nll/issue-98170.rs", -"ui/nll/issue-98589-closures-relate-named-regions.rs", -"ui/nll/issue-98693.rs", -"ui/nll/polonius/issue-46589.rs", -"ui/nll/relate_tys/issue-48071.rs", -"ui/nll/ty-outlives/issue-53789-1.rs", -"ui/nll/ty-outlives/issue-53789-2.rs", -"ui/nll/ty-outlives/issue-55756.rs", -"ui/nll/user-annotations/issue-54124.rs", -"ui/nll/user-annotations/issue-54570-bootstrapping.rs", -"ui/nll/user-annotations/issue-55219.rs", -"ui/nll/user-annotations/issue-55241.rs", -"ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs", -"ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs", -"ui/numbers-arithmetic/issue-105626.rs", -"ui/numbers-arithmetic/issue-8460.rs", -"ui/object-safety/issue-102762.rs", -"ui/object-safety/issue-102933.rs", -"ui/object-safety/issue-106247.rs", -"ui/object-safety/issue-19538.rs", -"ui/on-unimplemented/issue-104140.rs", -"ui/or-patterns/issue-64879-trailing-before-guard.rs", -"ui/or-patterns/issue-67514-irrefutable-param.rs", -"ui/or-patterns/issue-68785-irrefutable-param-with-at.rs", -"ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs", -"ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs", -"ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs", -"ui/overloaded/issue-14958.rs", -"ui/packed/issue-118537-field-offset-ice.rs", -"ui/packed/issue-118537-field-offset.rs", -"ui/packed/issue-27060-2.rs", -"ui/packed/issue-27060.rs", -"ui/packed/issue-46152.rs", -"ui/panics/issue-47429-short-backtraces.rs", -"ui/parser/issue-116781.rs", -"ui/parser/issues/auxiliary/issue-21146-inc.rs", -"ui/parser/issues/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs", -"ui/parser/issues/auxiliary/issue-94340-inc.rs", -"ui/parser/issues/issue-100197-mut-let.rs", -"ui/parser/issues/issue-101477-enum.rs", -"ui/parser/issues/issue-101477-let.rs", -"ui/parser/issues/issue-101540.rs", -"ui/parser/issues/issue-102182-impl-trait-recover.rs", -"ui/parser/issues/issue-102806.rs", -"ui/parser/issues/issue-103143.rs", -"ui/parser/issues/issue-103381.rs", -"ui/parser/issues/issue-103425.rs", -"ui/parser/issues/issue-103451.rs", -"ui/parser/issues/issue-103748-ICE-wrong-braces.rs", -"ui/parser/issues/issue-10392-2.rs", -"ui/parser/issues/issue-10392.rs", -"ui/parser/issues/issue-104367.rs", -"ui/parser/issues/issue-104620.rs", -"ui/parser/issues/issue-104867-inc-dec-2.rs", -"ui/parser/issues/issue-104867-inc-dec.rs", -"ui/parser/issues/issue-105209.rs", -"ui/parser/issues/issue-105366.rs", -"ui/parser/issues/issue-105634.rs", -"ui/parser/issues/issue-10636-1.rs", -"ui/parser/issues/issue-10636-2.rs", -"ui/parser/issues/issue-107705.rs", -"ui/parser/issues/issue-108109-fn-missing-params.rs", -"ui/parser/issues/issue-108109-fn-trait-missing-paren.rs", -"ui/parser/issues/issue-108242-semicolon-recovery.rs", -"ui/parser/issues/issue-108495-dec.rs", -"ui/parser/issues/issue-110014.rs", -"ui/parser/issues/issue-111148.rs", -"ui/parser/issues/issue-111416.rs", -"ui/parser/issues/issue-111692.rs", -"ui/parser/issues/issue-112188.rs", -"ui/parser/issues/issue-112458.rs", -"ui/parser/issues/issue-113110-non-item-at-module-root.rs", -"ui/parser/issues/issue-113203.rs", -"ui/parser/issues/issue-113342.rs", -"ui/parser/issues/issue-114219.rs", -"ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs", -"ui/parser/issues/issue-118530-ice.rs", -"ui/parser/issues/issue-118531-ice.rs", -"ui/parser/issues/issue-13483.rs", -"ui/parser/issues/issue-14303-fncall.rs", -"ui/parser/issues/issue-14303.rs", -"ui/parser/issues/issue-15914.rs", -"ui/parser/issues/issue-15980.rs", -"ui/parser/issues/issue-1655.rs", -"ui/parser/issues/issue-17718-const-mut.rs", -"ui/parser/issues/issue-17718-parse-const.rs", -"ui/parser/issues/issue-17904-2.rs", -"ui/parser/issues/issue-17904.rs", -"ui/parser/issues/issue-1802-1.rs", -"ui/parser/issues/issue-1802-2.rs", -"ui/parser/issues/issue-19096.rs", -"ui/parser/issues/issue-19398.rs", -"ui/parser/issues/issue-20616-1.rs", -"ui/parser/issues/issue-20616-2.rs", -"ui/parser/issues/issue-20616-3.rs", -"ui/parser/issues/issue-20616-4.rs", -"ui/parser/issues/issue-20616-5.rs", -"ui/parser/issues/issue-20616-6.rs", -"ui/parser/issues/issue-20616-7.rs", -"ui/parser/issues/issue-20616-8.rs", -"ui/parser/issues/issue-20616-9.rs", -"ui/parser/issues/issue-20711-2.rs", -"ui/parser/issues/issue-20711.rs", -"ui/parser/issues/issue-21146.rs", -"ui/parser/issues/issue-21153.rs", -"ui/parser/issues/issue-21475.rs", -"ui/parser/issues/issue-22647.rs", -"ui/parser/issues/issue-22712.rs", -"ui/parser/issues/issue-2354-1.rs", -"ui/parser/issues/issue-2354.rs", -"ui/parser/issues/issue-23620-invalid-escapes.rs", -"ui/parser/issues/issue-24197.rs", -"ui/parser/issues/issue-24375.rs", -"ui/parser/issues/issue-24780.rs", -"ui/parser/issues/issue-27255.rs", -"ui/parser/issues/issue-30318.rs", -"ui/parser/issues/issue-3036.rs", -"ui/parser/issues/issue-31804.rs", -"ui/parser/issues/issue-32214.rs", -"ui/parser/issues/issue-32446.rs", -"ui/parser/issues/issue-32501.rs", -"ui/parser/issues/issue-32505.rs", -"ui/parser/issues/issue-33262.rs", -"ui/parser/issues/issue-33413.rs", -"ui/parser/issues/issue-33418.rs", -"ui/parser/issues/issue-33455.rs", -"ui/parser/issues/issue-34222-1.rs", -"ui/parser/issues/issue-34255-1.rs", -"ui/parser/issues/issue-35813-postfix-after-cast.rs", -"ui/parser/issues/issue-39616.rs", -"ui/parser/issues/issue-41155.rs", -"ui/parser/issues/issue-43196.rs", -"ui/parser/issues/issue-43692.rs", -"ui/parser/issues/issue-44021.rs", -"ui/parser/issues/issue-44406.rs", -"ui/parser/issues/issue-45296.rs", -"ui/parser/issues/issue-46186.rs", -"ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs", -"ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items.rs", -"ui/parser/issues/issue-48508-aux.rs", -"ui/parser/issues/issue-48508.rs", -"ui/parser/issues/issue-48636.rs", -"ui/parser/issues/issue-49040.rs", -"ui/parser/issues/issue-49257.rs", -"ui/parser/issues/issue-51602.rs", -"ui/parser/issues/issue-52496.rs", -"ui/parser/issues/issue-54521-1.rs", -"ui/parser/issues/issue-54521-2.rs", -"ui/parser/issues/issue-54521-3.rs", -"ui/parser/issues/issue-5544-a.rs", -"ui/parser/issues/issue-5544-b.rs", -"ui/parser/issues/issue-56031.rs", -"ui/parser/issues/issue-57198.rs", -"ui/parser/issues/issue-57684.rs", -"ui/parser/issues/issue-57819.rs", -"ui/parser/issues/issue-5806.rs", -"ui/parser/issues/issue-58094-missing-right-square-bracket.rs", -"ui/parser/issues/issue-58856-1.rs", -"ui/parser/issues/issue-58856-2.rs", -"ui/parser/issues/issue-59418.rs", -"ui/parser/issues/issue-60075.rs", -"ui/parser/issues/issue-61858.rs", -"ui/parser/issues/issue-62524.rs", -"ui/parser/issues/issue-62546.rs", -"ui/parser/issues/issue-62554.rs", -"ui/parser/issues/issue-62660.rs", -"ui/parser/issues/issue-62881.rs", -"ui/parser/issues/issue-62894.rs", -"ui/parser/issues/issue-62895.rs", -"ui/parser/issues/issue-62913.rs", -"ui/parser/issues/issue-62973.rs", -"ui/parser/issues/issue-63115-range-pat-interpolated.rs", -"ui/parser/issues/issue-63116.rs", -"ui/parser/issues/issue-63135.rs", -"ui/parser/issues/issue-64732.rs", -"ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs", -"ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs", -"ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs", -"ui/parser/issues/issue-65257-invalid-var-decl-recovery.rs", -"ui/parser/issues/issue-65846-rollback-gating-failing-matcher.rs", -"ui/parser/issues/issue-6610.rs", -"ui/parser/issues/issue-66357-unexpected-unreachable.rs", -"ui/parser/issues/issue-66473.rs", -"ui/parser/issues/issue-67146-negative-outlives-bound-syntactic-fail.rs", -"ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs", -"ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.rs", -"ui/parser/issues/issue-68091-unicode-ident-after-if.rs", -"ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs", -"ui/parser/issues/issue-68629.rs", -"ui/parser/issues/issue-68730.rs", -"ui/parser/issues/issue-68788-in-trait-item-propagation.rs", -"ui/parser/issues/issue-68890-2.rs", -"ui/parser/issues/issue-68890.rs", -"ui/parser/issues/issue-68987-unmatch-issue-1.rs", -"ui/parser/issues/issue-68987-unmatch-issue-2.rs", -"ui/parser/issues/issue-68987-unmatch-issue-3.rs", -"ui/parser/issues/issue-68987-unmatch-issue.rs", -"ui/parser/issues/issue-69259.rs", -"ui/parser/issues/issue-70050-ntliteral-accepts-negated-lit.rs", -"ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.rs", -"ui/parser/issues/issue-70388-without-witness.rs", -"ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.rs", -"ui/parser/issues/issue-70552-ascription-in-parens-after-call.rs", -"ui/parser/issues/issue-70583-block-is-empty-1.rs", -"ui/parser/issues/issue-70583-block-is-empty-2.rs", -"ui/parser/issues/issue-7222.rs", -"ui/parser/issues/issue-72253.rs", -"ui/parser/issues/issue-72373.rs", -"ui/parser/issues/issue-73568-lifetime-after-mut.rs", -"ui/parser/issues/issue-75599.rs", -"ui/parser/issues/issue-76437-async.rs", -"ui/parser/issues/issue-76437-const-async-unsafe.rs", -"ui/parser/issues/issue-76437-const-async.rs", -"ui/parser/issues/issue-76437-const.rs", -"ui/parser/issues/issue-76437-pub-crate-unsafe.rs", -"ui/parser/issues/issue-76437-unsafe.rs", -"ui/parser/issues/issue-76597.rs", -"ui/parser/issues/issue-7970b.rs", -"ui/parser/issues/issue-81804.rs", -"ui/parser/issues/issue-81806.rs", -"ui/parser/issues/issue-81827.rs", -"ui/parser/issues/issue-83639.rs", -"ui/parser/issues/issue-84104.rs", -"ui/parser/issues/issue-84117.rs", -"ui/parser/issues/issue-84148-1.rs", -"ui/parser/issues/issue-84148-2.rs", -"ui/parser/issues/issue-8537.rs", -"ui/parser/issues/issue-86895.rs", -"ui/parser/issues/issue-87086-colon-path-sep.rs", -"ui/parser/issues/issue-87197-missing-semicolon.rs", -"ui/parser/issues/issue-87635.rs", -"ui/parser/issues/issue-87694-duplicated-pub.rs", -"ui/parser/issues/issue-87694-misplaced-pub.rs", -"ui/parser/issues/issue-87812-path.rs", -"ui/parser/issues/issue-87812.rs", -"ui/parser/issues/issue-88276-unary-plus.rs", -"ui/parser/issues/issue-88583-union-as-ident.rs", -"ui/parser/issues/issue-88770.rs", -"ui/parser/issues/issue-88818.rs", -"ui/parser/issues/issue-89388.rs", -"ui/parser/issues/issue-89396.rs", -"ui/parser/issues/issue-89574.rs", -"ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs", -"ui/parser/issues/issue-90728.rs", -"ui/parser/issues/issue-90993.rs", -"ui/parser/issues/issue-91421.rs", -"ui/parser/issues/issue-91461.rs", -"ui/parser/issues/issue-93282.rs", -"ui/parser/issues/issue-93867.rs", -"ui/parser/issues/issue-94340.rs", -"ui/parser/issues/issue-98601-delimiter-error-1.rs", -"ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs", -"ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.rs", -"ui/parser/issues/issue-99910-const-let-mutually-exclusive.rs", -"ui/parser/macro/issue-33569.rs", -"ui/parser/macro/issue-37113.rs", -"ui/parser/macro/issue-37234.rs", -"ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs", -"ui/parser/shebang/issue-71471-ignore-tidy.rs", -"ui/pattern/issue-10392.rs", -"ui/pattern/issue-106552.rs", -"ui/pattern/issue-106862.rs", -"ui/pattern/issue-110508.rs", -"ui/pattern/issue-115599.rs", -"ui/pattern/issue-11577.rs", -"ui/pattern/issue-117626.rs", -"ui/pattern/issue-12582.rs", -"ui/pattern/issue-14221.rs", -"ui/pattern/issue-15080.rs", -"ui/pattern/issue-17718-patterns.rs", -"ui/pattern/issue-22546.rs", -"ui/pattern/issue-27320.rs", -"ui/pattern/issue-28992-empty.rs", -"ui/pattern/issue-52240.rs", -"ui/pattern/issue-6449.rs", -"ui/pattern/issue-66270-pat-struct-parser-recovery.rs", -"ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs", -"ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs", -"ui/pattern/issue-68393-let-pat-assoc-constant.rs", -"ui/pattern/issue-72565.rs", -"ui/pattern/issue-72574-1.rs", -"ui/pattern/issue-72574-2.rs", -"ui/pattern/issue-74539.rs", -"ui/pattern/issue-74702.rs", -"ui/pattern/issue-74954.rs", -"ui/pattern/issue-80186-mut-binding-help-suggestion.rs", -"ui/pattern/issue-8351-1.rs", -"ui/pattern/issue-8351-2.rs", -"ui/pattern/issue-88074-pat-range-type-inference-err.rs", -"ui/pattern/issue-88074-pat-range-type-inference.rs", -"ui/pattern/issue-92074-macro-ice.rs", -"ui/pattern/issue-94866.rs", -"ui/pattern/issue-95878.rs", -"ui/pattern/move-ref-patterns/issue-53840.rs", -"ui/pattern/usefulness/integer-ranges/issue-117648-overlapping_range_endpoints-false-positive.rs", -"ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs", -"ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs", -"ui/pattern/usefulness/issue-119493-type-error-ice.rs", -"ui/pattern/usefulness/issue-119778-type-error-ice.rs", -"ui/pattern/usefulness/issue-12116.rs", -"ui/pattern/usefulness/issue-12369.rs", -"ui/pattern/usefulness/issue-13727.rs", -"ui/pattern/usefulness/issue-15129.rs", -"ui/pattern/usefulness/issue-2111.rs", -"ui/pattern/usefulness/issue-30240-b.rs", -"ui/pattern/usefulness/issue-30240-rpass.rs", -"ui/pattern/usefulness/issue-30240.rs", -"ui/pattern/usefulness/issue-3096-1.rs", -"ui/pattern/usefulness/issue-3096-2.rs", -"ui/pattern/usefulness/issue-31221.rs", -"ui/pattern/usefulness/issue-31561.rs", -"ui/pattern/usefulness/issue-35609.rs", -"ui/pattern/usefulness/issue-3601.rs", -"ui/pattern/usefulness/issue-39362.rs", -"ui/pattern/usefulness/issue-40221.rs", -"ui/pattern/usefulness/issue-4321.rs", -"ui/pattern/usefulness/issue-50900.rs", -"ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs", -"ui/pattern/usefulness/issue-56379.rs", -"ui/pattern/usefulness/issue-57472.rs", -"ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs", -"ui/pattern/usefulness/issue-66501.rs", -"ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs", -"ui/pattern/usefulness/issue-72377.rs", -"ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs", -"ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs", -"ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs", -"ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs", -"ui/pattern/usefulness/issue-82772-match-box-as-struct.rs", -"ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs", -"ui/pattern/usefulness/issue-88747.rs", -"ui/polymorphization/issue-74614.rs", -"ui/polymorphization/issue-74636.rs", -"ui/privacy/auxiliary/issue-117997.rs", -"ui/privacy/auxiliary/issue-119463-extern.rs", -"ui/privacy/auxiliary/issue-17718-const-privacy.rs", -"ui/privacy/auxiliary/issue-57264-1.rs", -"ui/privacy/auxiliary/issue-57264-2.rs", -"ui/privacy/auxiliary/issue-75907.rs", -"ui/privacy/auxiliary/issue-92755.rs", -"ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs", -"ui/privacy/issue-111220-tuple-struct-fields.rs", -"ui/privacy/issue-113860-1.rs", -"ui/privacy/issue-113860-2.rs", -"ui/privacy/issue-113860.rs", -"ui/privacy/issue-11593.rs", -"ui/privacy/issue-117997.rs", -"ui/privacy/issue-119463.rs", -"ui/privacy/issue-13641.rs", -"ui/privacy/issue-17718-const-privacy.rs", -"ui/privacy/issue-29161.rs", -"ui/privacy/issue-30079.rs", -"ui/privacy/issue-46209-private-enum-variant-reexport.rs", -"ui/privacy/issue-57264-1.rs", -"ui/privacy/issue-57264-2.rs", -"ui/privacy/issue-75062-fieldless-tuple-struct.rs", -"ui/privacy/issue-75906.rs", -"ui/privacy/issue-75907.rs", -"ui/privacy/issue-75907_b.rs", -"ui/privacy/issue-79593.rs", -"ui/privacy/issue-92755.rs", -"ui/proc-macro/auxiliary/issue-104884.rs", -"ui/proc-macro/auxiliary/issue-107113.rs", -"ui/proc-macro/auxiliary/issue-118809.rs", -"ui/proc-macro/auxiliary/issue-38586.rs", -"ui/proc-macro/auxiliary/issue-39889.rs", -"ui/proc-macro/auxiliary/issue-42708.rs", -"ui/proc-macro/auxiliary/issue-50061.rs", -"ui/proc-macro/auxiliary/issue-50493.rs", -"ui/proc-macro/auxiliary/issue-59191.rs", -"ui/proc-macro/auxiliary/issue-66286.rs", -"ui/proc-macro/auxiliary/issue-75801.rs", -"ui/proc-macro/auxiliary/issue-79242.rs", -"ui/proc-macro/auxiliary/issue-79825.rs", -"ui/proc-macro/auxiliary/issue-83510.rs", -"ui/proc-macro/auxiliary/issue-91800-macro.rs", -"ui/proc-macro/issue-104884-trait-impl-sugg-err.rs", -"ui/proc-macro/issue-107113-wrap.rs", -"ui/proc-macro/issue-118455-skip-err-builtin.rs", -"ui/proc-macro/issue-118809.rs", -"ui/proc-macro/issue-36935.rs", -"ui/proc-macro/issue-37788.rs", -"ui/proc-macro/issue-38586.rs", -"ui/proc-macro/issue-39889.rs", -"ui/proc-macro/issue-42708.rs", -"ui/proc-macro/issue-50061.rs", -"ui/proc-macro/issue-50493.rs", -"ui/proc-macro/issue-53481.rs", -"ui/proc-macro/issue-59191-replace-root-with-fn.rs", -"ui/proc-macro/issue-66286.rs", -"ui/proc-macro/issue-73933-procedural-masquerade.rs", -"ui/proc-macro/issue-75734-pp-paren.rs", -"ui/proc-macro/issue-75801.rs", -"ui/proc-macro/issue-75930-derive-cfg.rs", -"ui/proc-macro/issue-76182-leading-vert-pat.rs", -"ui/proc-macro/issue-76270-panic-in-libproc-macro.rs", -"ui/proc-macro/issue-78675-captured-inner-attrs.rs", -"ui/proc-macro/issue-79148.rs", -"ui/proc-macro/issue-79242-slow-retokenize-check.rs", -"ui/proc-macro/issue-79825.rs", -"ui/proc-macro/issue-80760-empty-stmt.rs", -"ui/proc-macro/issue-81007-item-attrs.rs", -"ui/proc-macro/issue-81543-item-parse-err.rs", -"ui/proc-macro/issue-81555.rs", -"ui/proc-macro/issue-83469-global-alloc-invalid-stmt.rs", -"ui/proc-macro/issue-83510.rs", -"ui/proc-macro/issue-86781-bad-inner-doc.rs", -"ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs", -"ui/proc-macro/issue-91800.rs", -"ui/process/issue-13304.rs", -"ui/process/issue-14456.rs", -"ui/process/issue-14940.rs", -"ui/process/issue-16272.rs", -"ui/process/issue-20091.rs", -"ui/process/issue-30490.rs", -"ui/ptr_ops/issue-80309-safe.rs", -"ui/ptr_ops/issue-80309.rs", -"ui/pub/issue-33174-restricted-type-in-public-interface.rs", -"ui/query-system/issue-83479.rs", -"ui/range/issue-54505-no-literals.rs", -"ui/range/issue-54505-no-std.rs", -"ui/range/issue-54505.rs", -"ui/range/issue-73553-misinterp-range-literal.rs", -"ui/reachable/auxiliary/issue-11225-1.rs", -"ui/reachable/auxiliary/issue-11225-2.rs", -"ui/reachable/auxiliary/issue-11225-3.rs", -"ui/reachable/issue-11225-1.rs", -"ui/reachable/issue-11225-2.rs", -"ui/reachable/issue-11225-3.rs", -"ui/reachable/issue-948.rs", -"ui/recursion/issue-26548-recursion-via-normalize.rs", -"ui/recursion/issue-38591-non-regular-dropck-recursion.rs", -"ui/recursion/issue-83150.rs", -"ui/recursion/issue-86784.rs", -"ui/recursion/issue-95134.rs", -"ui/recursion_limit/issue-105700.rs", -"ui/recursion_limit/issue-40003.rs", -"ui/regions/issue-101280.rs", -"ui/regions/issue-102374.rs", -"ui/regions/issue-102392.rs", -"ui/regions/issue-11612.rs", -"ui/regions/issue-12470.rs", -"ui/regions/issue-21520.rs", -"ui/regions/issue-24085.rs", -"ui/regions/issue-26448-1.rs", -"ui/regions/issue-26448-2.rs", -"ui/regions/issue-26448-3.rs", -"ui/regions/issue-28848.rs", -"ui/regions/issue-5243.rs", -"ui/regions/issue-56537-closure-uses-region-from-container.rs", -"ui/regions/issue-6157.rs", -"ui/regions/issue-72051-member-region-hang.rs", -"ui/regions/issue-78262.rs", -"ui/repr/issue-83505-repr-simd.rs", -"ui/resolve/auxiliary/issue-112831-aux.rs", -"ui/resolve/auxiliary/issue-19452-aux.rs", -"ui/resolve/auxiliary/issue-21221-3.rs", -"ui/resolve/auxiliary/issue-21221-4.rs", -"ui/resolve/auxiliary/issue-30535.rs", -"ui/resolve/auxiliary/issue-3907.rs", -"ui/resolve/auxiliary/issue-80079.rs", -"ui/resolve/issue-100365.rs", -"ui/resolve/issue-101749-2.rs", -"ui/resolve/issue-101749.rs", -"ui/resolve/issue-10200.rs", -"ui/resolve/issue-102946.rs", -"ui/resolve/issue-103202.rs", -"ui/resolve/issue-103474.rs", -"ui/resolve/issue-104700-inner_scope.rs", -"ui/resolve/issue-105069.rs", -"ui/resolve/issue-107563-ambiguous-glob-reexports.rs", -"ui/resolve/issue-108529.rs", -"ui/resolve/issue-109153.rs", -"ui/resolve/issue-109250.rs", -"ui/resolve/issue-111312.rs", -"ui/resolve/issue-111727.rs", -"ui/resolve/issue-112472-multi-generics-suggestion.rs", -"ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs", -"ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs", -"ui/resolve/issue-116164.rs", -"ui/resolve/issue-117920.rs", -"ui/resolve/issue-118295.rs", -"ui/resolve/issue-120559.rs", -"ui/resolve/issue-12796.rs", -"ui/resolve/issue-14254.rs", -"ui/resolve/issue-16058.rs", -"ui/resolve/issue-17518.rs", -"ui/resolve/issue-18252.rs", -"ui/resolve/issue-19452.rs", -"ui/resolve/issue-21221-1.rs", -"ui/resolve/issue-21221-2.rs", -"ui/resolve/issue-21221-3.rs", -"ui/resolve/issue-21221-4.rs", -"ui/resolve/issue-22692.rs", -"ui/resolve/issue-2330.rs", -"ui/resolve/issue-23305.rs", -"ui/resolve/issue-2356.rs", -"ui/resolve/issue-23716.rs", -"ui/resolve/issue-24968.rs", -"ui/resolve/issue-26545.rs", -"ui/resolve/issue-3021-c.rs", -"ui/resolve/issue-3021.rs", -"ui/resolve/issue-30535.rs", -"ui/resolve/issue-3099-a.rs", -"ui/resolve/issue-3099-b.rs", -"ui/resolve/issue-31845.rs", -"ui/resolve/issue-33876.rs", -"ui/resolve/issue-35675.rs", -"ui/resolve/issue-3907-2.rs", -"ui/resolve/issue-3907.rs", -"ui/resolve/issue-39226.rs", -"ui/resolve/issue-39559-2.rs", -"ui/resolve/issue-39559.rs", -"ui/resolve/issue-42944.rs", -"ui/resolve/issue-49074.rs", -"ui/resolve/issue-5035-2.rs", -"ui/resolve/issue-5035.rs", -"ui/resolve/issue-50599.rs", -"ui/resolve/issue-5099.rs", -"ui/resolve/issue-54379.rs", -"ui/resolve/issue-55673.rs", -"ui/resolve/issue-57523.rs", -"ui/resolve/issue-5927.rs", -"ui/resolve/issue-60057.rs", -"ui/resolve/issue-65025-extern-static-parent-generics.rs", -"ui/resolve/issue-65035-static-with-parent-generics.rs", -"ui/resolve/issue-6642.rs", -"ui/resolve/issue-6702.rs", -"ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs", -"ui/resolve/issue-70736-async-fn-no-body-def-collector.rs", -"ui/resolve/issue-73427.rs", -"ui/resolve/issue-80079.rs", -"ui/resolve/issue-81508.rs", -"ui/resolve/issue-82156.rs", -"ui/resolve/issue-82865.rs", -"ui/resolve/issue-85348.rs", -"ui/resolve/issue-85671.rs", -"ui/resolve/issue-88472.rs", -"ui/resolve/issue-90113.rs", -"ui/return/issue-64620.rs", -"ui/return/issue-82612-return-mutable-reference.rs", -"ui/return/issue-86188-return-not-in-fn-body.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs", -"ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs", -"ui/rfcs/rfc-1937-termination-trait/issue-103052-1.rs", -"ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs", -"ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs", -"ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs", -"ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs", -"ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs", -"ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs", -"ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs", -"ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs", -"ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs", -"ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs", -"ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs", -"ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs", -"ui/rust-2018/issue-51008-1.rs", -"ui/rust-2018/issue-51008.rs", -"ui/rust-2018/issue-52202-use-suggestions.rs", -"ui/rust-2018/issue-54006.rs", -"ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-55779-extern-trait.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-56596.rs", -"ui/rust-2018/uniform-paths/auxiliary/issue-87932-a.rs", -"ui/rust-2018/uniform-paths/issue-54253.rs", -"ui/rust-2018/uniform-paths/issue-55779.rs", -"ui/rust-2018/uniform-paths/issue-56596-2.rs", -"ui/rust-2018/uniform-paths/issue-56596.rs", -"ui/rust-2018/uniform-paths/issue-87932.rs", -"ui/sanitizer/issue-111184-cfi-coroutine-witness.rs", -"ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs", -"ui/sanitizer/issue-72154-address-lifetime-markers.rs", -"ui/self/issue-61882-2.rs", -"ui/self/issue-61882.rs", -"ui/simd/intrinsic/issue-85855.rs", -"ui/simd/issue-105439.rs", -"ui/simd/issue-17170.rs", -"ui/simd/issue-32947.rs", -"ui/simd/issue-39720.rs", -"ui/simd/issue-85915-simd-ptrs.rs", -"ui/simd/issue-89193.rs", -"ui/single-use-lifetime/issue-104440.rs", -"ui/single-use-lifetime/issue-107998.rs", -"ui/single-use-lifetime/issue-117965.rs", -"ui/span/issue-107353.rs", -"ui/span/issue-11925.rs", -"ui/span/issue-15480.rs", -"ui/span/issue-23338-locals-die-before-temps-of-body.rs", -"ui/span/issue-23729.rs", -"ui/span/issue-23827.rs", -"ui/span/issue-24356.rs", -"ui/span/issue-24690.rs", -"ui/span/issue-24805-dropck-child-has-items-via-parent.rs", -"ui/span/issue-24805-dropck-trait-has-items.rs", -"ui/span/issue-24895-copy-clone-dropck.rs", -"ui/span/issue-25199.rs", -"ui/span/issue-26656.rs", -"ui/span/issue-27522.rs", -"ui/span/issue-29106.rs", -"ui/span/issue-29595.rs", -"ui/span/issue-33884.rs", -"ui/span/issue-34264.rs", -"ui/span/issue-35987.rs", -"ui/span/issue-36537.rs", -"ui/span/issue-37767.rs", -"ui/span/issue-39018.rs", -"ui/span/issue-39698.rs", -"ui/span/issue-40157.rs", -"ui/span/issue-42234-unknown-receiver-type.rs", -"ui/span/issue-43927-non-ADT-derive.rs", -"ui/span/issue-71363.rs", -"ui/span/issue-81800.rs", -"ui/span/issue28498-reject-ex1.rs", -"ui/span/issue28498-reject-lifetime-param.rs", -"ui/span/issue28498-reject-passed-to-fn.rs", -"ui/span/issue28498-reject-trait-bound.rs", -"ui/specialization/issue-111232.rs", -"ui/specialization/issue-33017.rs", -"ui/specialization/issue-35376.rs", -"ui/specialization/issue-36804.rs", -"ui/specialization/issue-38091-2.rs", -"ui/specialization/issue-38091.rs", -"ui/specialization/issue-39448.rs", -"ui/specialization/issue-39618.rs", -"ui/specialization/issue-40582.rs", -"ui/specialization/issue-43037.rs", -"ui/specialization/issue-44861.rs", -"ui/specialization/issue-45814.rs", -"ui/specialization/issue-50452-fail.rs", -"ui/specialization/issue-50452.rs", -"ui/specialization/issue-51892.rs", -"ui/specialization/issue-52050.rs", -"ui/specialization/issue-59435.rs", -"ui/specialization/issue-63716-parse-async.rs", -"ui/specialization/issue-68830-spurious-diagnostics.rs", -"ui/specialization/issue-70442.rs", -"ui/specialization/min_specialization/issue-79224.rs", -"ui/stability-attribute/issue-106589.rs", -"ui/stability-attribute/issue-109177.rs", -"ui/stability-attribute/issue-28075.rs", -"ui/stability-attribute/issue-28388-3.rs", -"ui/stability-attribute/issue-99286-stable-intrinsics.rs", -"ui/static/auxiliary/issue_24843.rs", -"ui/static/issue-1660.rs", -"ui/static/issue-18118-2.rs", -"ui/static/issue-18118.rs", -"ui/static/issue-24446.rs", -"ui/static/issue-24843.rs", -"ui/static/issue-34194.rs", -"ui/static/issue-5216.rs", -"ui/statics/issue-14227.rs", -"ui/statics/issue-15261.rs", -"ui/statics/issue-17233.rs", -"ui/statics/issue-17718-static-sync.rs", -"ui/statics/issue-17718-static-unsafe-interior.rs", -"ui/statics/issue-44373-2.rs", -"ui/statics/issue-44373.rs", -"ui/statics/issue-91050-1.rs", -"ui/statics/issue-91050-2.rs", -"ui/std/issue-3563-3.rs", -"ui/std/issue-81357-unsound-file-methods.rs", -"ui/stdlib-unit-tests/issue-21058.rs", -"ui/structs-enums/enum-rec/issue-17431-6.rs", -"ui/structs-enums/enum-rec/issue-17431-7.rs", -"ui/structs-enums/issue-103869.rs", -"ui/structs-enums/issue-1701.rs", -"ui/structs-enums/issue-2718-a.rs", -"ui/structs-enums/issue-3008-1.rs", -"ui/structs-enums/issue-3008-2.rs", -"ui/structs-enums/issue-3008-3.rs", -"ui/structs-enums/issue-38002.rs", -"ui/structs-enums/issue-50731.rs", -"ui/structs-enums/struct-rec/issue-17431-1.rs", -"ui/structs-enums/struct-rec/issue-17431-2.rs", -"ui/structs-enums/struct-rec/issue-17431-3.rs", -"ui/structs-enums/struct-rec/issue-17431-4.rs", -"ui/structs-enums/struct-rec/issue-17431-5.rs", -"ui/structs-enums/struct-rec/issue-74224.rs", -"ui/structs-enums/struct-rec/issue-84611.rs", -"ui/structs/issue-80853.rs", -"ui/suggestions/auxiliary/issue-61963-1.rs", -"ui/suggestions/auxiliary/issue-61963.rs", -"ui/suggestions/auxiliary/issue-81839.rs", -"ui/suggestions/issue-101065.rs", -"ui/suggestions/issue-101421.rs", -"ui/suggestions/issue-101465.rs", -"ui/suggestions/issue-101623.rs", -"ui/suggestions/issue-101984.rs", -"ui/suggestions/issue-102354.rs", -"ui/suggestions/issue-102892.rs", -"ui/suggestions/issue-102972.rs", -"ui/suggestions/issue-103112.rs", -"ui/suggestions/issue-103646.rs", -"ui/suggestions/issue-104086-suggest-let.rs", -"ui/suggestions/issue-104287.rs", -"ui/suggestions/issue-104327.rs", -"ui/suggestions/issue-104328.rs", -"ui/suggestions/issue-104961.rs", -"ui/suggestions/issue-105226.rs", -"ui/suggestions/issue-105494.rs", -"ui/suggestions/issue-105645.rs", -"ui/suggestions/issue-105761-suggest-self-for-closure.rs", -"ui/suggestions/issue-106443-sugg-clone-for-arg.rs", -"ui/suggestions/issue-106443-sugg-clone-for-bound.rs", -"ui/suggestions/issue-107860.rs", -"ui/suggestions/issue-108470.rs", -"ui/suggestions/issue-109195.rs", -"ui/suggestions/issue-109291.rs", -"ui/suggestions/issue-109396.rs", -"ui/suggestions/issue-109436.rs", -"ui/suggestions/issue-109854.rs", -"ui/suggestions/issue-109991.rs", -"ui/suggestions/issue-112590-suggest-import.rs", -"ui/suggestions/issue-114701.rs", -"ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs", -"ui/suggestions/issue-116434-2015.rs", -"ui/suggestions/issue-116434-2021.rs", -"ui/suggestions/issue-117669.rs", -"ui/suggestions/issue-21673.rs", -"ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs", -"ui/suggestions/issue-52820.rs", -"ui/suggestions/issue-53692.rs", -"ui/suggestions/issue-57672.rs", -"ui/suggestions/issue-59819.rs", -"ui/suggestions/issue-61226.rs", -"ui/suggestions/issue-61963.rs", -"ui/suggestions/issue-62843.rs", -"ui/suggestions/issue-64252-self-type.rs", -"ui/suggestions/issue-66968-suggest-sorted-words.rs", -"ui/suggestions/issue-68049-1.rs", -"ui/suggestions/issue-68049-2.rs", -"ui/suggestions/issue-71394-no-from-impl.rs", -"ui/suggestions/issue-72766.rs", -"ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs", -"ui/suggestions/issue-81098.rs", -"ui/suggestions/issue-81839.rs", -"ui/suggestions/issue-82361.rs", -"ui/suggestions/issue-82566-1.rs", -"ui/suggestions/issue-82566-2.rs", -"ui/suggestions/issue-83892.rs", -"ui/suggestions/issue-83943.rs", -"ui/suggestions/issue-84592.rs", -"ui/suggestions/issue-84700.rs", -"ui/suggestions/issue-84973-2.rs", -"ui/suggestions/issue-84973-blacklist.rs", -"ui/suggestions/issue-84973-negative.rs", -"ui/suggestions/issue-84973.rs", -"ui/suggestions/issue-85347.rs", -"ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs", -"ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs", -"ui/suggestions/issue-86100-tuple-paren-comma.rs", -"ui/suggestions/issue-86667.rs", -"ui/suggestions/issue-88696.rs", -"ui/suggestions/issue-88730.rs", -"ui/suggestions/issue-89064.rs", -"ui/suggestions/issue-89333.rs", -"ui/suggestions/issue-89640.rs", -"ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs", -"ui/suggestions/issue-90974.rs", -"ui/suggestions/issue-94171.rs", -"ui/suggestions/issue-96223.rs", -"ui/suggestions/issue-96555.rs", -"ui/suggestions/issue-97677.rs", -"ui/suggestions/issue-97704.rs", -"ui/suggestions/issue-97760.rs", -"ui/suggestions/issue-98500.rs", -"ui/suggestions/issue-98562.rs", -"ui/suggestions/issue-99080.rs", -"ui/suggestions/issue-99240-2.rs", -"ui/suggestions/issue-99240.rs", -"ui/suggestions/issue-99597.rs", -"ui/suggestions/lifetimes/issue-105544.rs", -"ui/symbol-names/issue-53912.rs", -"ui/symbol-names/issue-60925.rs", -"ui/symbol-names/issue-75326.rs", -"ui/symbol-names/issue-76365.rs", -"ui/test-attrs/custom-test-frameworks/issue-107454.rs", -"ui/test-attrs/issue-109816.rs", -"ui/test-attrs/issue-12997-1.rs", -"ui/test-attrs/issue-12997-2.rs", -"ui/test-attrs/issue-16597-empty.rs", -"ui/test-attrs/issue-16597.rs", -"ui/test-attrs/issue-20823.rs", -"ui/test-attrs/issue-34932.rs", -"ui/test-attrs/issue-36768.rs", -"ui/test-attrs/issue-52557.rs", -"ui/test-attrs/issue-53675-a-test-called-panic.rs", -"ui/threads-sendsync/issue-24313.rs", -"ui/threads-sendsync/issue-29488.rs", -"ui/threads-sendsync/issue-43733-2.rs", -"ui/threads-sendsync/issue-43733.rs", -"ui/threads-sendsync/issue-4446.rs", -"ui/threads-sendsync/issue-4448.rs", -"ui/threads-sendsync/issue-8827.rs", -"ui/threads-sendsync/issue-9396.rs", -"ui/trait-bounds/issue-119530-sugg-from-fn.rs", -"ui/trait-bounds/issue-75961.rs", -"ui/trait-bounds/issue-82038.rs", -"ui/trait-bounds/issue-93008.rs", -"ui/trait-bounds/issue-94680.rs", -"ui/trait-bounds/issue-94999.rs", -"ui/trait-bounds/issue-95640.rs", -"ui/traits/alias/issue-107747-do-not-assemble-supertraits.rs", -"ui/traits/alias/issue-108072-unmet-trait-alias-bound.rs", -"ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs", -"ui/traits/alias/issue-60021-assoc-method-resolve.rs", -"ui/traits/alias/issue-60755.rs", -"ui/traits/alias/issue-72415-assoc-const-resolve.rs", -"ui/traits/alias/issue-75983.rs", -"ui/traits/alias/issue-83613.rs", -"ui/traits/associated_type_bound/issue-51446.rs", -"ui/traits/auxiliary/issue_89119_intercrate_caching.rs", -"ui/traits/issue-103563.rs", -"ui/traits/issue-104322.rs", -"ui/traits/issue-105231.rs", -"ui/traits/issue-106072.rs", -"ui/traits/issue-117794.rs", -"ui/traits/issue-15155.rs", -"ui/traits/issue-18400.rs", -"ui/traits/issue-18412.rs", -"ui/traits/issue-20692.rs", -"ui/traits/issue-21837.rs", -"ui/traits/issue-22019.rs", -"ui/traits/issue-22110.rs", -"ui/traits/issue-22384.rs", -"ui/traits/issue-22655.rs", -"ui/traits/issue-23003-overflow.rs", -"ui/traits/issue-23003.rs", -"ui/traits/issue-23825.rs", -"ui/traits/issue-24010.rs", -"ui/traits/issue-26339.rs", -"ui/traits/issue-28576.rs", -"ui/traits/issue-32963.rs", -"ui/traits/issue-33096.rs", -"ui/traits/issue-33140-hack-boundaries.rs", -"ui/traits/issue-33140.rs", -"ui/traits/issue-33187.rs", -"ui/traits/issue-35869.rs", -"ui/traits/issue-3683.rs", -"ui/traits/issue-38033.rs", -"ui/traits/issue-38404.rs", -"ui/traits/issue-38604.rs", -"ui/traits/issue-3973.rs", -"ui/traits/issue-3979-generics.rs", -"ui/traits/issue-40085.rs", -"ui/traits/issue-4107.rs", -"ui/traits/issue-43132.rs", -"ui/traits/issue-43784-supertrait.rs", -"ui/traits/issue-5008-borrowed-traitobject-method-call.rs", -"ui/traits/issue-50480.rs", -"ui/traits/issue-52893.rs", -"ui/traits/issue-56202.rs", -"ui/traits/issue-56488.rs", -"ui/traits/issue-58344.rs", -"ui/traits/issue-59029-1.rs", -"ui/traits/issue-59029-2.rs", -"ui/traits/issue-6128.rs", -"ui/traits/issue-6334.rs", -"ui/traits/issue-65284-suggest-generic-trait-bound.rs", -"ui/traits/issue-65673.rs", -"ui/traits/issue-66768.rs", -"ui/traits/issue-68295.rs", -"ui/traits/issue-7013.rs", -"ui/traits/issue-70944.rs", -"ui/traits/issue-71036.rs", -"ui/traits/issue-71136.rs", -"ui/traits/issue-72410.rs", -"ui/traits/issue-72455.rs", -"ui/traits/issue-75627.rs", -"ui/traits/issue-77982.rs", -"ui/traits/issue-78372.rs", -"ui/traits/issue-78632.rs", -"ui/traits/issue-79458.rs", -"ui/traits/issue-8153.rs", -"ui/traits/issue-82830.rs", -"ui/traits/issue-83538-tainted-cache-after-cycle.rs", -"ui/traits/issue-84399-bad-fresh-caching.rs", -"ui/traits/issue-85360-eval-obligation-ice.rs", -"ui/traits/issue-85735.rs", -"ui/traits/issue-87558.rs", -"ui/traits/issue-89119.rs", -"ui/traits/issue-90195-2.rs", -"ui/traits/issue-90195.rs", -"ui/traits/issue-90662-projection-caching.rs", -"ui/traits/issue-91594.rs", -"ui/traits/issue-91949-hangs-on-recursion.rs", -"ui/traits/issue-92292.rs", -"ui/traits/issue-9394-inherited-calls.rs", -"ui/traits/issue-95311.rs", -"ui/traits/issue-95898.rs", -"ui/traits/issue-96664.rs", -"ui/traits/issue-96665.rs", -"ui/traits/issue-97576.rs", -"ui/traits/issue-97695-double-trivial-bound.rs", -"ui/traits/issue-99875.rs", -"ui/traits/next-solver/coherence/issue-102048.rs", -"ui/traits/next-solver/issue-118950-root-region.rs", -"ui/traits/object/issue-33140-traitobject-crate.rs", -"ui/traits/object/issue-44454-1.rs", -"ui/traits/object/issue-44454-2.rs", -"ui/traits/object/issue-44454-3.rs", -"ui/traits/suggest-dereferences/issue-39029.rs", -"ui/traits/suggest-dereferences/issue-62530.rs", -"ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs", -"ui/traits/trait-upcasting/issue-11515.rs", -"ui/traits/vtable/issue-91807.rs", -"ui/traits/vtable/issue-97381.rs", -"ui/transmutability/arrays/issue-103783-array-length.rs", -"ui/transmutability/issue-101739-1.rs", -"ui/transmutability/issue-101739-2.rs", -"ui/transmutability/issue-110467.rs", -"ui/transmutability/issue-110892.rs", -"ui/trivial-bounds/issue-73021-impossible-inline.rs", -"ui/try-block/issue-45124.rs", -"ui/try-trait/issue-32709.rs", -"ui/type-alias-enum-variants/issue-57866.rs", -"ui/type-alias-enum-variants/issue-61801-path-pattern-can-infer.rs", -"ui/type-alias-enum-variants/issue-63151-dead-code-lint-fields-in-patterns.rs", -"ui/type-alias-impl-trait/issue-101750.rs", -"ui/type-alias-impl-trait/issue-104817.rs", -"ui/type-alias-impl-trait/issue-109054.rs", -"ui/type-alias-impl-trait/issue-52843-closure-constrain.rs", -"ui/type-alias-impl-trait/issue-52843.rs", -"ui/type-alias-impl-trait/issue-53092-2.rs", -"ui/type-alias-impl-trait/issue-53092.rs", -"ui/type-alias-impl-trait/issue-53096.rs", -"ui/type-alias-impl-trait/issue-53398-cyclic-types.rs", -"ui/type-alias-impl-trait/issue-53598.rs", -"ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs", -"ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs", -"ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs", -"ui/type-alias-impl-trait/issue-57611-trait-alias.rs", -"ui/type-alias-impl-trait/issue-57700.rs", -"ui/type-alias-impl-trait/issue-57807-associated-type.rs", -"ui/type-alias-impl-trait/issue-57961.rs", -"ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs", -"ui/type-alias-impl-trait/issue-58662-simplified.rs", -"ui/type-alias-impl-trait/issue-58887.rs", -"ui/type-alias-impl-trait/issue-58951-2.rs", -"ui/type-alias-impl-trait/issue-58951.rs", -"ui/type-alias-impl-trait/issue-60371.rs", -"ui/type-alias-impl-trait/issue-60407.rs", -"ui/type-alias-impl-trait/issue-60564-working.rs", -"ui/type-alias-impl-trait/issue-60564.rs", -"ui/type-alias-impl-trait/issue-60662.rs", -"ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs", -"ui/type-alias-impl-trait/issue-63263-closure-return.rs", -"ui/type-alias-impl-trait/issue-63279.rs", -"ui/type-alias-impl-trait/issue-63355.rs", -"ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs", -"ui/type-alias-impl-trait/issue-65384.rs", -"ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs", -"ui/type-alias-impl-trait/issue-65918.rs", -"ui/type-alias-impl-trait/issue-66580-closure-coherence.rs", -"ui/type-alias-impl-trait/issue-67844-nested-opaque.rs", -"ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs", -"ui/type-alias-impl-trait/issue-68368-non-defining-use.rs", -"ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs", -"ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-ok.rs", -"ui/type-alias-impl-trait/issue-69323.rs", -"ui/type-alias-impl-trait/issue-70121.rs", -"ui/type-alias-impl-trait/issue-72793.rs", -"ui/type-alias-impl-trait/issue-74244.rs", -"ui/type-alias-impl-trait/issue-74280.rs", -"ui/type-alias-impl-trait/issue-74761-2.rs", -"ui/type-alias-impl-trait/issue-74761.rs", -"ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs", -"ui/type-alias-impl-trait/issue-77179.rs", -"ui/type-alias-impl-trait/issue-78450.rs", -"ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs", -"ui/type-alias-impl-trait/issue-84660-unsoundness.rs", -"ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs", -"ui/type-alias-impl-trait/issue-89686.rs", -"ui/type-alias-impl-trait/issue-89952.rs", -"ui/type-alias-impl-trait/issue-90400-1.rs", -"ui/type-alias-impl-trait/issue-90400-2.rs", -"ui/type-alias-impl-trait/issue-93411.rs", -"ui/type-alias-impl-trait/issue-94429.rs", -"ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs", -"ui/type-alias-impl-trait/issue-96572-unconstrained.rs", -"ui/type-alias-impl-trait/issue-98604.rs", -"ui/type-alias-impl-trait/issue-98608.rs", -"ui/type-alias/issue-14933.rs", -"ui/type-alias/issue-37515.rs", -"ui/type-alias/issue-62263-self-in-atb.rs", -"ui/type-alias/issue-62305-self-assoc-ty.rs", -"ui/type-alias/issue-62364-self-ty-arg.rs", -"ui/type-inference/issue-113283-alllocator-trait-eq.rs", -"ui/type-inference/issue-30225.rs", -"ui/type/ascription/issue-34255-1.rs", -"ui/type/ascription/issue-47666.rs", -"ui/type/ascription/issue-54516.rs", -"ui/type/ascription/issue-60933.rs", -"ui/type/issue-100584.rs", -"ui/type/issue-101866.rs", -"ui/type/issue-102598.rs", -"ui/type/issue-103271.rs", -"ui/type/issue-58355.rs", -"ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs", -"ui/type/issue-91268.rs", -"ui/type/issue-94187-verbose-type-name.rs", -"ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs", -"ui/type/type-check/issue-22897.rs", -"ui/type/type-check/issue-40294.rs", -"ui/type/type-check/issue-41314.rs", -"ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs", -"ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs", -"ui/typeck/auxiliary/issue-29181.rs", -"ui/typeck/auxiliary/issue-36708.rs", -"ui/typeck/auxiliary/issue-81943-lib.rs", -"ui/typeck/issue-100164.rs", -"ui/typeck/issue-100246.rs", -"ui/typeck/issue-100285.rs", -"ui/typeck/issue-103899.rs", -"ui/typeck/issue-10401.rs", -"ui/typeck/issue-104510-ice.rs", -"ui/typeck/issue-104513-ice.rs", -"ui/typeck/issue-104582.rs", -"ui/typeck/issue-105946.rs", -"ui/typeck/issue-106929.rs", -"ui/typeck/issue-107087.rs", -"ui/typeck/issue-107775.rs", -"ui/typeck/issue-10969.rs", -"ui/typeck/issue-110017-format-into-help-deletes-macro.rs", -"ui/typeck/issue-110052.rs", -"ui/typeck/issue-112007-leaked-writeln-macro-internals.rs", -"ui/typeck/issue-112252-ptr-arithmetics-help.rs", -"ui/typeck/issue-112385-while-assign-lhs-place-expr-ice.rs", -"ui/typeck/issue-114423-ice-regression-in-suggestion.rs", -"ui/typeck/issue-114529-illegal-break-with-value.rs", -"ui/typeck/issue-116473-ice-wrong-span-variant-args.rs", -"ui/typeck/issue-116864.rs", -"ui/typeck/issue-120856.rs", -"ui/typeck/issue-13853-2.rs", -"ui/typeck/issue-13853-5.rs", -"ui/typeck/issue-13853.rs", -"ui/typeck/issue-16338.rs", -"ui/typeck/issue-1871.rs", -"ui/typeck/issue-18937-1.rs", -"ui/typeck/issue-18937.rs", -"ui/typeck/issue-2063-resource.rs", -"ui/typeck/issue-2063.rs", -"ui/typeck/issue-22375.rs", -"ui/typeck/issue-29124.rs", -"ui/typeck/issue-29181.rs", -"ui/typeck/issue-31173.rs", -"ui/typeck/issue-33575.rs", -"ui/typeck/issue-36708.rs", -"ui/typeck/issue-43189.rs", -"ui/typeck/issue-46112.rs", -"ui/typeck/issue-50687-ice-on-borrow.rs", -"ui/typeck/issue-52082-type-param-shadows-existing-type.rs", -"ui/typeck/issue-53712.rs", -"ui/typeck/issue-55810-must-typeck-match-pats-before-guards.rs", -"ui/typeck/issue-57404.rs", -"ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs", -"ui/typeck/issue-61711-once-caused-rustc-inf-loop.rs", -"ui/typeck/issue-65611.rs", -"ui/typeck/issue-67971.rs", -"ui/typeck/issue-68590-reborrow-through-derefmut.rs", -"ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.rs", -"ui/typeck/issue-72225-call-fnmut-through-derefmut.rs", -"ui/typeck/issue-73592-borrow_mut-through-deref.rs", -"ui/typeck/issue-74086.rs", -"ui/typeck/issue-74933.rs", -"ui/typeck/issue-75883.rs", -"ui/typeck/issue-75889.rs", -"ui/typeck/issue-7813.rs", -"ui/typeck/issue-79040.rs", -"ui/typeck/issue-80207-unsized-return.rs", -"ui/typeck/issue-80779.rs", -"ui/typeck/issue-81293.rs", -"ui/typeck/issue-81885.rs", -"ui/typeck/issue-81943.rs", -"ui/typeck/issue-82772.rs", -"ui/typeck/issue-83621-placeholder-static-in-extern.rs", -"ui/typeck/issue-83693.rs", -"ui/typeck/issue-84160.rs", -"ui/typeck/issue-84768.rs", -"ui/typeck/issue-84831.rs", -"ui/typeck/issue-86721-return-expr-ice.rs", -"ui/typeck/issue-87771-ice-assign-assign-to-bool.rs", -"ui/typeck/issue-87872-missing-inaccessible-field-literal.rs", -"ui/typeck/issue-87872-missing-inaccessible-field-pattern.rs", -"ui/typeck/issue-88609.rs", -"ui/typeck/issue-88643.rs", -"ui/typeck/issue-88803-call-expr-method.rs", -"ui/typeck/issue-88844.rs", -"ui/typeck/issue-89044-wrapped-expr-method.rs", -"ui/typeck/issue-89275.rs", -"ui/typeck/issue-89806.rs", -"ui/typeck/issue-89856.rs", -"ui/typeck/issue-89935.rs", -"ui/typeck/issue-90027-async-fn-return-suggestion.rs", -"ui/typeck/issue-90101.rs", -"ui/typeck/issue-90164.rs", -"ui/typeck/issue-90319.rs", -"ui/typeck/issue-90483-inaccessible-field-adjustment.rs", -"ui/typeck/issue-90804-incorrect-reference-suggestion.rs", -"ui/typeck/issue-91210-ptr-method.rs", -"ui/typeck/issue-91267.rs", -"ui/typeck/issue-91328.rs", -"ui/typeck/issue-91334.rs", -"ui/typeck/issue-91450-inner-ty-error.rs", -"ui/typeck/issue-91633.rs", -"ui/typeck/issue-92481.rs", -"ui/typeck/issue-93486.rs", -"ui/typeck/issue-96530.rs", -"ui/typeck/issue-96738.rs", -"ui/typeck/issue-98260.rs", -"ui/typeck/issue-98982.rs", -"ui/typeof/issue-100183.rs", -"ui/typeof/issue-29184.rs", -"ui/typeof/issue-42060.rs", -"ui/unboxed-closures/issue-18652.rs", -"ui/unboxed-closures/issue-18661.rs", -"ui/unboxed-closures/issue-30906.rs", -"ui/unboxed-closures/issue-53448.rs", -"ui/underscore-imports/issue-110164.rs", -"ui/uniform-paths/auxiliary/issue-53691.rs", -"ui/uniform-paths/issue-53691.rs", -"ui/uninhabited/issue-107505.rs", -"ui/union/issue-41073.rs", -"ui/union/issue-81199.rs", -"ui/union/issue-99375.rs", -"ui/unsafe/auxiliary/issue-106126.rs", -"ui/unsafe/issue-106126-good-path-bug.rs", -"ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs", -"ui/unsafe/issue-3080.rs", -"ui/unsafe/issue-45087-unreachable-unsafe.rs", -"ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs", -"ui/unsafe/issue-47412.rs", -"ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs", -"ui/unsafe/issue-87414-query-cycle.rs", -"ui/unsized-locals/issue-30276-feature-flagged.rs", -"ui/unsized-locals/issue-30276.rs", -"ui/unsized-locals/issue-50940-with-feature.rs", -"ui/unsized-locals/issue-50940.rs", -"ui/unsized-locals/issue-67981.rs", -"ui/unsized/issue-115203.rs", -"ui/unsized/issue-115809.rs", -"ui/unsized/issue-30355.rs", -"ui/unsized/issue-40231-1.rs", -"ui/unsized/issue-40231-2.rs", -"ui/unsized/issue-71659.rs", -"ui/unsized/issue-75707.rs", -"ui/unsized/issue-75899-but-gats.rs", -"ui/unsized/issue-75899.rs", -"ui/unsized/issue-91801.rs", -"ui/unsized/issue-91803.rs", -"ui/unsized/issue-97732.rs", -"ui/use/issue-18986.rs", -"ui/use/issue-60976-extern-use-primitive-type.rs", -"ui/wf/issue-103573.rs", -"ui/wf/issue-110157.rs", -"ui/wf/issue-48638.rs", -"ui/wf/issue-87495.rs", -"ui/wf/issue-95665.rs", -"ui/wf/issue-96810.rs", -"ui/where-clauses/issue-50825-1.rs", -"ui/where-clauses/issue-50825.rs", -] +ui/abi/issue-28676.rs +ui/abi/issues/issue-22565-rust-call.rs +ui/abi/issues/issue-62350-sysv-neg-reg-counts.rs +ui/abi/issues/issue-97463-broken-abi-leaked-uninit-data.rs +ui/argument-suggestions/issue-100154.rs +ui/argument-suggestions/issue-100478.rs +ui/argument-suggestions/issue-101097.rs +ui/argument-suggestions/issue-109425.rs +ui/argument-suggestions/issue-109831.rs +ui/argument-suggestions/issue-112507.rs +ui/argument-suggestions/issue-96638.rs +ui/argument-suggestions/issue-97197.rs +ui/argument-suggestions/issue-97484.rs +ui/argument-suggestions/issue-98894.rs +ui/argument-suggestions/issue-98897.rs +ui/argument-suggestions/issue-99482.rs +ui/array-slice-vec/issue-15730.rs +ui/array-slice-vec/issue-18425.rs +ui/array-slice-vec/issue-69103-extra-binding-subslice.rs +ui/asm/issue-113788.rs +ui/asm/issue-72570.rs +ui/asm/issue-85247.rs +ui/asm/issue-87802.rs +ui/asm/issue-89305.rs +ui/asm/issue-92378.rs +ui/asm/issue-97490.rs +ui/asm/issue-99071.rs +ui/asm/issue-99122-2.rs +ui/asm/issue-99122.rs +ui/asm/x86_64/issue-82869.rs +ui/asm/x86_64/issue-89875.rs +ui/asm/x86_64/issue-96797.rs +ui/associated-consts/issue-102335-const.rs +ui/associated-consts/issue-105330.rs +ui/associated-consts/issue-110933.rs +ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.rs +ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.rs +ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.rs +ui/associated-consts/issue-47814.rs +ui/associated-consts/issue-58022.rs +ui/associated-consts/issue-63496.rs +ui/associated-consts/issue-69020-assoc-const-arith-overflow.rs +ui/associated-consts/issue-88599-ref-self.rs +ui/associated-consts/issue-93775.rs +ui/associated-consts/issue-93835.rs +ui/associated-inherent-types/issue-104260.rs +ui/associated-inherent-types/issue-109071.rs +ui/associated-inherent-types/issue-109299-1.rs +ui/associated-inherent-types/issue-109299.rs +ui/associated-inherent-types/issue-109768.rs +ui/associated-inherent-types/issue-109789.rs +ui/associated-inherent-types/issue-109790.rs +ui/associated-inherent-types/issue-111404-0.rs +ui/associated-inherent-types/issue-111404-1.rs +ui/associated-inherent-types/issue-111879-0.rs +ui/associated-inherent-types/issue-111879-1.rs +ui/associated-item/issue-105449.rs +ui/associated-item/issue-48027.rs +ui/associated-item/issue-87638.rs +ui/associated-type-bounds/issue-102335-ty.rs +ui/associated-type-bounds/issue-104916.rs +ui/associated-type-bounds/issue-61752.rs +ui/associated-type-bounds/issue-70292.rs +ui/associated-type-bounds/issue-71443-1.rs +ui/associated-type-bounds/issue-71443-2.rs +ui/associated-type-bounds/issue-73818.rs +ui/associated-type-bounds/issue-79949.rs +ui/associated-type-bounds/issue-81193.rs +ui/associated-type-bounds/issue-83017.rs +ui/associated-type-bounds/issue-99828.rs +ui/associated-type-bounds/return-type-notation/issue-120208-higher-ranked-const.rs +ui/associated-types/issue-18655.rs +ui/associated-types/issue-19081.rs +ui/associated-types/issue-19883.rs +ui/associated-types/issue-20005.rs +ui/associated-types/issue-20825-2.rs +ui/associated-types/issue-20825.rs +ui/associated-types/issue-21363.rs +ui/associated-types/issue-21726.rs +ui/associated-types/issue-22037.rs +ui/associated-types/issue-22066.rs +ui/associated-types/issue-22560.rs +ui/associated-types/issue-22828.rs +ui/associated-types/issue-23208.rs +ui/associated-types/issue-23595-1.rs +ui/associated-types/issue-23595-2.rs +ui/associated-types/issue-24159.rs +ui/associated-types/issue-24204.rs +ui/associated-types/issue-24338.rs +ui/associated-types/issue-25339.rs +ui/associated-types/issue-25700-1.rs +ui/associated-types/issue-25700-2.rs +ui/associated-types/issue-25700.rs +ui/associated-types/issue-26262.rs +ui/associated-types/issue-26681.rs +ui/associated-types/issue-27675-unchecked-bounds.rs +ui/associated-types/issue-27901.rs +ui/associated-types/issue-28871.rs +ui/associated-types/issue-31597.rs +ui/associated-types/issue-32323.rs +ui/associated-types/issue-32350.rs +ui/associated-types/issue-36499.rs +ui/associated-types/issue-37808.rs +ui/associated-types/issue-37883.rs +ui/associated-types/issue-38821.rs +ui/associated-types/issue-38917.rs +ui/associated-types/issue-39532.rs +ui/associated-types/issue-40093.rs +ui/associated-types/issue-41868.rs +ui/associated-types/issue-43475.rs +ui/associated-types/issue-43784-associated-type.rs +ui/associated-types/issue-43924.rs +ui/associated-types/issue-44153.rs +ui/associated-types/issue-47139-1.rs +ui/associated-types/issue-47139-2.rs +ui/associated-types/issue-47385.rs +ui/associated-types/issue-47814.rs +ui/associated-types/issue-48010.rs +ui/associated-types/issue-48551.rs +ui/associated-types/issue-50301.rs +ui/associated-types/issue-54108.rs +ui/associated-types/issue-54182-1.rs +ui/associated-types/issue-54182-2.rs +ui/associated-types/issue-54467.rs +ui/associated-types/issue-55846.rs +ui/associated-types/issue-59324.rs +ui/associated-types/issue-62200.rs +ui/associated-types/issue-63591.rs +ui/associated-types/issue-63593.rs +ui/associated-types/issue-64848.rs +ui/associated-types/issue-64855-2.rs +ui/associated-types/issue-64855.rs +ui/associated-types/issue-65774-1.rs +ui/associated-types/issue-65774-2.rs +ui/associated-types/issue-65934.rs +ui/associated-types/issue-67684.rs +ui/associated-types/issue-69398.rs +ui/associated-types/issue-71113.rs +ui/associated-types/issue-72806.rs +ui/associated-types/issue-76179.rs +ui/associated-types/issue-82079.rs +ui/associated-types/issue-85103-layout-debug.rs +ui/associated-types/issue-87261.rs +ui/associated-types/issue-88856.rs +ui/associated-types/issue-91069.rs +ui/associated-types/issue-91231.rs +ui/associated-types/issue-91234.rs +ui/async-await/auxiliary/issue-107036.rs +ui/async-await/auxiliary/issue-72470-lib.rs +ui/async-await/in-trait/issue-102138.rs +ui/async-await/in-trait/issue-102219.rs +ui/async-await/in-trait/issue-102310.rs +ui/async-await/in-trait/issue-104678.rs +ui/async-await/issue-101715.rs +ui/async-await/issue-105501.rs +ui/async-await/issue-107036.rs +ui/async-await/issue-108572.rs +ui/async-await/issue-54239-private-type-triggers-lint.rs +ui/async-await/issue-60709.rs +ui/async-await/issue-61076.rs +ui/async-await/issue-61452.rs +ui/async-await/issue-61793.rs +ui/async-await/issue-62658.rs +ui/async-await/issue-63832-await-short-temporary-lifetime-1.rs +ui/async-await/issue-63832-await-short-temporary-lifetime.rs +ui/async-await/issue-64130-1-sync.rs +ui/async-await/issue-64130-2-send.rs +ui/async-await/issue-64130-3-other.rs +ui/async-await/issue-64130-4-async-move.rs +ui/async-await/issue-64130-non-send-future-diags.rs +ui/async-await/issue-64391.rs +ui/async-await/issue-65634-raw-ident-suggestion.rs +ui/async-await/issue-66312.rs +ui/async-await/issue-66387-if-without-else.rs +ui/async-await/issue-67252-unnamed-future.rs +ui/async-await/issue-67651.rs +ui/async-await/issue-67765-async-diagnostic.rs +ui/async-await/issue-68112.rs +ui/async-await/issue-68523-start.rs +ui/async-await/issue-68523.rs +ui/async-await/issue-69446-fnmut-capture.rs +ui/async-await/issue-70594.rs +ui/async-await/issue-70818.rs +ui/async-await/issue-70935-complex-spans.rs +ui/async-await/issue-71137.rs +ui/async-await/issue-72442.rs +ui/async-await/issue-72470-llvm-dominate.rs +ui/async-await/issue-72590-type-error-sized.rs +ui/async-await/issue-73050.rs +ui/async-await/issue-73137.rs +ui/async-await/issue-73541-1.rs +ui/async-await/issue-73541-2.rs +ui/async-await/issue-73541-3.rs +ui/async-await/issue-73541.rs +ui/async-await/issue-73741-type-err.rs +ui/async-await/issue-74047.rs +ui/async-await/issue-74072-lifetime-name-annotations.rs +ui/async-await/issue-74497-lifetime-in-opaque.rs +ui/async-await/issue-75785-confusing-named-region.rs +ui/async-await/issue-76547.rs +ui/async-await/issue-77993-2.rs +ui/async-await/issue-78115.rs +ui/async-await/issue-84841.rs +ui/async-await/issue-86507.rs +ui/async-await/issue-93197.rs +ui/async-await/issue-93648.rs +ui/async-await/issue-98634.rs +ui/async-await/issues/auxiliary/issue-60674.rs +ui/async-await/issues/auxiliary/issue_67893.rs +ui/async-await/issues/issue-102206.rs +ui/async-await/issues/issue-107280.rs +ui/async-await/issues/issue-112225-1.rs +ui/async-await/issues/issue-112225-2.rs +ui/async-await/issues/issue-51719.rs +ui/async-await/issues/issue-51751.rs +ui/async-await/issues/issue-53249.rs +ui/async-await/issues/issue-54752-async-block.rs +ui/async-await/issues/issue-54974.rs +ui/async-await/issues/issue-55324.rs +ui/async-await/issues/issue-55809.rs +ui/async-await/issues/issue-58885.rs +ui/async-await/issues/issue-59001.rs +ui/async-await/issues/issue-59972.rs +ui/async-await/issues/issue-60518.rs +ui/async-await/issues/issue-60655-latebound-regions.rs +ui/async-await/issues/issue-60674.rs +ui/async-await/issues/issue-61187.rs +ui/async-await/issues/issue-61986.rs +ui/async-await/issues/issue-62009-1.rs +ui/async-await/issues/issue-62009-2.rs +ui/async-await/issues/issue-62097.rs +ui/async-await/issues/issue-62517-1.rs +ui/async-await/issues/issue-62517-2.rs +ui/async-await/issues/issue-63388-1.rs +ui/async-await/issues/issue-63388-2.rs +ui/async-await/issues/issue-63388-3.rs +ui/async-await/issues/issue-63388-4.rs +ui/async-await/issues/issue-64391-2.rs +ui/async-await/issues/issue-64433.rs +ui/async-await/issues/issue-64477-2.rs +ui/async-await/issues/issue-64477.rs +ui/async-await/issues/issue-64964.rs +ui/async-await/issues/issue-65159.rs +ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-completion.rs +ui/async-await/issues/issue-65419/issue-65419-async-fn-resume-after-panic.rs +ui/async-await/issues/issue-65419/issue-65419-coroutine-resume-after-completion.rs +ui/async-await/issues/issue-65436-raw-ptr-not-send.rs +ui/async-await/issues/issue-66695-static-refs.rs +ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs +ui/async-await/issues/issue-67611-static-mut-refs.rs +ui/async-await/issues/issue-67893.rs +ui/async-await/issues/issue-69307-nested.rs +ui/async-await/issues/issue-69307.rs +ui/async-await/issues/issue-72312.rs +ui/async-await/issues/issue-78600.rs +ui/async-await/issues/issue-78654.rs +ui/async-await/issues/issue-78938-async-block.rs +ui/async-await/issues/issue-95307.rs +ui/async-await/return-type-notation/issue-110963-early.rs +ui/async-await/return-type-notation/issue-110963-late.rs +ui/async-await/track-caller/issue-105134.rs +ui/attributes/issue-100631.rs +ui/attributes/issue-105594-invalid-attr-validation.rs +ui/attributes/issue-115264-expr-field.rs +ui/attributes/issue-115264-pat-field.rs +ui/attributes/issue-40962.rs +ui/attributes/issue-90873.rs +ui/auto-traits/issue-117789.rs +ui/auto-traits/issue-23080-2.rs +ui/auto-traits/issue-23080.rs +ui/auto-traits/issue-83857-ub.rs +ui/auto-traits/issue-84075.rs +ui/auxiliary/issue-13560-1.rs +ui/auxiliary/issue-13560-2.rs +ui/auxiliary/issue-13560-3.rs +ui/auxiliary/issue-16822.rs +ui/auxiliary/issue-18502.rs +ui/auxiliary/issue-24106.rs +ui/auxiliary/issue-76387.rs +ui/bench/issue-32062.rs +ui/binding/issue-53114-borrow-checks.rs +ui/binding/issue-53114-safety-checks.rs +ui/binop/issue-25916.rs +ui/binop/issue-28837.rs +ui/binop/issue-3820.rs +ui/binop/issue-62375.rs +ui/binop/issue-77910-1.rs +ui/binop/issue-77910-2.rs +ui/binop/issue-93927.rs +ui/block-result/issue-11714.rs +ui/block-result/issue-13428.rs +ui/block-result/issue-13624.rs +ui/block-result/issue-20862.rs +ui/block-result/issue-22645.rs +ui/block-result/issue-3563.rs +ui/block-result/issue-5500.rs +ui/borrowck/issue-101119.rs +ui/borrowck/issue-102209.rs +ui/borrowck/issue-103095.rs +ui/borrowck/issue-103250.rs +ui/borrowck/issue-103624.rs +ui/borrowck/issue-104639-lifetime-order.rs +ui/borrowck/issue-10876.rs +ui/borrowck/issue-109271-pass-self-into-closure.rs +ui/borrowck/issue-111554.rs +ui/borrowck/issue-114374-invalid-help-fmt-args.rs +ui/borrowck/issue-11493.rs +ui/borrowck/issue-115259-suggest-iter-mut.rs +ui/borrowck/issue-119915-bad-clone-suggestion.rs +ui/borrowck/issue-17263.rs +ui/borrowck/issue-17545.rs +ui/borrowck/issue-17718-static-move.rs +ui/borrowck/issue-20801.rs +ui/borrowck/issue-23338-params-outlive-temps-of-body.rs +ui/borrowck/issue-24267-flow-exit.rs +ui/borrowck/issue-25793.rs +ui/borrowck/issue-28934.rs +ui/borrowck/issue-29166.rs +ui/borrowck/issue-31287-drop-in-guard.rs +ui/borrowck/issue-33819.rs +ui/borrowck/issue-36082.rs +ui/borrowck/issue-41962.rs +ui/borrowck/issue-42344.rs +ui/borrowck/issue-45199.rs +ui/borrowck/issue-45983.rs +ui/borrowck/issue-46095.rs +ui/borrowck/issue-46471.rs +ui/borrowck/issue-47215-ice-from-drop-elab.rs +ui/borrowck/issue-47646.rs +ui/borrowck/issue-51117.rs +ui/borrowck/issue-51301.rs +ui/borrowck/issue-51348-multi-ref-mut-in-guard.rs +ui/borrowck/issue-51415.rs +ui/borrowck/issue-52713-bug.rs +ui/borrowck/issue-52967-edition-2018-needs-two-phase-borrows.rs +ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.rs +ui/borrowck/issue-54499-field-mutation-marks-mut-as-used.rs +ui/borrowck/issue-54499-field-mutation-of-moved-out-with-mut.rs +ui/borrowck/issue-54499-field-mutation-of-moved-out.rs +ui/borrowck/issue-54499-field-mutation-of-never-init.rs +ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.rs +ui/borrowck/issue-55492-borrowck-migrate-scans-parents.rs +ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs +ui/borrowck/issue-58776-borrowck-scans-children.rs +ui/borrowck/issue-62007-assign-box.rs +ui/borrowck/issue-62007-assign-field.rs +ui/borrowck/issue-62107-match-arm-scopes.rs +ui/borrowck/issue-62387-suggest-iter-mut-2.rs +ui/borrowck/issue-62387-suggest-iter-mut.rs +ui/borrowck/issue-64453.rs +ui/borrowck/issue-69789-iterator-mut-suggestion.rs +ui/borrowck/issue-70919-drop-in-loop.rs +ui/borrowck/issue-71546.rs +ui/borrowck/issue-7573.rs +ui/borrowck/issue-80772.rs +ui/borrowck/issue-81365-1.rs +ui/borrowck/issue-81365-10.rs +ui/borrowck/issue-81365-11.rs +ui/borrowck/issue-81365-2.rs +ui/borrowck/issue-81365-3.rs +ui/borrowck/issue-81365-4.rs +ui/borrowck/issue-81365-5.rs +ui/borrowck/issue-81365-6.rs +ui/borrowck/issue-81365-7.rs +ui/borrowck/issue-81365-8.rs +ui/borrowck/issue-81365-9.rs +ui/borrowck/issue-81899.rs +ui/borrowck/issue-82032.rs +ui/borrowck/issue-82126-mismatched-subst-and-hir.rs +ui/borrowck/issue-82462.rs +ui/borrowck/issue-83309-ice-immut-in-for-loop.rs +ui/borrowck/issue-83760.rs +ui/borrowck/issue-83924.rs +ui/borrowck/issue-85581.rs +ui/borrowck/issue-85765-closure.rs +ui/borrowck/issue-85765.rs +ui/borrowck/issue-87456-point-to-closure.rs +ui/borrowck/issue-88434-minimal-example.rs +ui/borrowck/issue-88434-removal-index-should-be-less.rs +ui/borrowck/issue-91206.rs +ui/borrowck/issue-92015.rs +ui/borrowck/issue-92157.rs +ui/borrowck/issue-93078.rs +ui/borrowck/issue-93093.rs +ui/borrowck/issue-95079-missing-move-in-nested-closure.rs +ui/box/issue-82446.rs +ui/box/issue-95036.rs +ui/c-variadic/issue-32201.rs +ui/c-variadic/issue-86053-1.rs +ui/c-variadic/issue-86053-2.rs +ui/cast/issue-106883-is-empty.rs +ui/cast/issue-10991.rs +ui/cast/issue-17444.rs +ui/cast/issue-84213.rs +ui/cast/issue-85586.rs +ui/cast/issue-88621.rs +ui/cast/issue-89497.rs +ui/closure-expected-type/issue-24421.rs +ui/closure_context/issue-26046-fn-mut.rs +ui/closure_context/issue-26046-fn-once.rs +ui/closure_context/issue-42065.rs +ui/closures/2229_closure_analysis/issue-118144.rs +ui/closures/2229_closure_analysis/issue-87378.rs +ui/closures/2229_closure_analysis/issue-87987.rs +ui/closures/2229_closure_analysis/issue-88118-2.rs +ui/closures/2229_closure_analysis/issue-88476.rs +ui/closures/2229_closure_analysis/issue-89606.rs +ui/closures/2229_closure_analysis/issue-90465.rs +ui/closures/2229_closure_analysis/issue-92724-needsdrop-query-cycle.rs +ui/closures/2229_closure_analysis/issue_88118.rs +ui/closures/2229_closure_analysis/match/issue-87097.rs +ui/closures/2229_closure_analysis/match/issue-87426.rs +ui/closures/2229_closure_analysis/match/issue-87988.rs +ui/closures/2229_closure_analysis/match/issue-88331.rs +ui/closures/2229_closure_analysis/migrations/issue-78720.rs +ui/closures/2229_closure_analysis/migrations/issue-86753.rs +ui/closures/2229_closure_analysis/migrations/issue-90024-adt-correct-subst.rs +ui/closures/2229_closure_analysis/run_pass/issue-87378.rs +ui/closures/2229_closure_analysis/run_pass/issue-88372.rs +ui/closures/2229_closure_analysis/run_pass/issue-88431.rs +ui/closures/2229_closure_analysis/run_pass/issue-88476.rs +ui/closures/issue-101696.rs +ui/closures/issue-102089-multiple-opaque-cast.rs +ui/closures/issue-10398.rs +ui/closures/issue-10682.rs +ui/closures/issue-109188.rs +ui/closures/issue-111932.rs +ui/closures/issue-113087.rs +ui/closures/issue-11873.rs +ui/closures/issue-1460.rs +ui/closures/issue-23012-supertrait-signature-inference.rs +ui/closures/issue-25439.rs +ui/closures/issue-41366.rs +ui/closures/issue-42463.rs +ui/closures/issue-46742.rs +ui/closures/issue-48109.rs +ui/closures/issue-52437.rs +ui/closures/issue-67123.rs +ui/closures/issue-6801.rs +ui/closures/issue-68025.rs +ui/closures/issue-72408-nested-closures-exponential.rs +ui/closures/issue-78720.rs +ui/closures/issue-80313-mutable-borrow-in-closure.rs +ui/closures/issue-80313-mutable-borrow-in-move-closure.rs +ui/closures/issue-80313-mutation-in-closure.rs +ui/closures/issue-80313-mutation-in-move-closure.rs +ui/closures/issue-81700-mut-borrow.rs +ui/closures/issue-82438-mut-without-upvar.rs +ui/closures/issue-84044-drop-non-mut.rs +ui/closures/issue-84128.rs +ui/closures/issue-868.rs +ui/closures/issue-87461.rs +ui/closures/issue-87814-1.rs +ui/closures/issue-87814-2.rs +ui/closures/issue-90871.rs +ui/closures/issue-97607.rs +ui/closures/issue-99565.rs +ui/cmse-nonsecure/cmse-nonsecure-entry/issue-83475.rs +ui/codegen/auxiliary/issue-97708-aux.rs +ui/codegen/issue-101585-128bit-repeat.rs +ui/codegen/issue-16602-1.rs +ui/codegen/issue-16602-2.rs +ui/codegen/issue-16602-3.rs +ui/codegen/issue-27859.rs +ui/codegen/issue-28950.rs +ui/codegen/issue-55976.rs +ui/codegen/issue-63787.rs +ui/codegen/issue-64401.rs +ui/codegen/issue-79865-llvm-miscompile.rs +ui/codegen/issue-82833-slice-miscompile.rs +ui/codegen/issue-82859-slice-miscompile.rs +ui/codegen/issue-88043-bb-does-not-have-terminator.rs +ui/codegen/issue-97708.rs +ui/codegen/issue-99551.rs +ui/codemap_tests/issue-11715.rs +ui/codemap_tests/issue-28308.rs +ui/coercion/auxiliary/issue-39823.rs +ui/coercion/issue-101066.rs +ui/coercion/issue-14589.rs +ui/coercion/issue-26905-rpass.rs +ui/coercion/issue-26905.rs +ui/coercion/issue-36007.rs +ui/coercion/issue-37655.rs +ui/coercion/issue-3794.rs +ui/coercion/issue-39823.rs +ui/coercion/issue-53475.rs +ui/coercion/issue-73886.rs +ui/coercion/issue-88097.rs +ui/coherence/issue-85026.rs +ui/coherence/issue-99663-2.rs +ui/coherence/issue-99663.rs +ui/command/issue-10626.rs +ui/compare-method/issue-90444.rs +ui/conditional-compilation/issue-34028.rs +ui/confuse-field-and-method/issue-18343.rs +ui/confuse-field-and-method/issue-2392.rs +ui/confuse-field-and-method/issue-32128.rs +ui/confuse-field-and-method/issue-33784.rs +ui/const-generics/generic_arg_infer/issue-91614.rs +ui/const-generics/generic_const_exprs/auxiliary/issue-94287-aux.rs +ui/const-generics/generic_const_exprs/const_kind_expr/issue_114151.rs +ui/const-generics/generic_const_exprs/issue-100217.rs +ui/const-generics/generic_const_exprs/issue-100360.rs +ui/const-generics/generic_const_exprs/issue-102074.rs +ui/const-generics/generic_const_exprs/issue-102768.rs +ui/const-generics/generic_const_exprs/issue-105257.rs +ui/const-generics/generic_const_exprs/issue-105608.rs +ui/const-generics/generic_const_exprs/issue-109141.rs +ui/const-generics/generic_const_exprs/issue-62504.rs +ui/const-generics/generic_const_exprs/issue-69654.rs +ui/const-generics/generic_const_exprs/issue-72787.rs +ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.rs +ui/const-generics/generic_const_exprs/issue-73298.rs +ui/const-generics/generic_const_exprs/issue-73899.rs +ui/const-generics/generic_const_exprs/issue-74634.rs +ui/const-generics/generic_const_exprs/issue-74713.rs +ui/const-generics/generic_const_exprs/issue-76595.rs +ui/const-generics/generic_const_exprs/issue-79518-default_trait_method_normalization.rs +ui/const-generics/generic_const_exprs/issue-80561-incorrect-param-env.rs +ui/const-generics/generic_const_exprs/issue-80742.rs +ui/const-generics/generic_const_exprs/issue-82268.rs +ui/const-generics/generic_const_exprs/issue-83765.rs +ui/const-generics/generic_const_exprs/issue-83972.rs +ui/const-generics/generic_const_exprs/issue-84408.rs +ui/const-generics/generic_const_exprs/issue-84669.rs +ui/const-generics/generic_const_exprs/issue-85848.rs +ui/const-generics/generic_const_exprs/issue-86710.rs +ui/const-generics/generic_const_exprs/issue-89851.rs +ui/const-generics/generic_const_exprs/issue-90847.rs +ui/const-generics/generic_const_exprs/issue-94287.rs +ui/const-generics/generic_const_exprs/issue-94293.rs +ui/const-generics/generic_const_exprs/issue-96699.rs +ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs +ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs +ui/const-generics/generic_const_exprs/issue-99647.rs +ui/const-generics/generic_const_exprs/issue-99705.rs +ui/const-generics/infer/issue-77092.rs +ui/const-generics/issue-102124.rs +ui/const-generics/issue-105689.rs +ui/const-generics/issue-106419-struct-with-multiple-const-params.rs +ui/const-generics/issue-112505-overflow.rs +ui/const-generics/issue-46511.rs +ui/const-generics/issue-66451.rs +ui/const-generics/issue-70408.rs +ui/const-generics/issue-80471.rs +ui/const-generics/issue-93647.rs +ui/const-generics/issue-97007.rs +ui/const-generics/issues/issue-100313.rs +ui/const-generics/issues/issue-105037.rs +ui/const-generics/issues/issue-105821.rs +ui/const-generics/issues/issue-56445-1.rs +ui/const-generics/issues/issue-56445-2.rs +ui/const-generics/issues/issue-56445-3.rs +ui/const-generics/issues/issue-60818-struct-constructors.rs +ui/const-generics/issues/issue-61336-1.rs +ui/const-generics/issues/issue-61336-2.rs +ui/const-generics/issues/issue-61336.rs +ui/const-generics/issues/issue-61422.rs +ui/const-generics/issues/issue-61432.rs +ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs +ui/const-generics/issues/issue-62878.rs +ui/const-generics/issues/issue-63322-forbid-dyn.rs +ui/const-generics/issues/issue-64519.rs +ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs +ui/const-generics/issues/issue-66906.rs +ui/const-generics/issues/issue-67185-1.rs +ui/const-generics/issues/issue-67185-2.rs +ui/const-generics/issues/issue-67375.rs +ui/const-generics/issues/issue-67739.rs +ui/const-generics/issues/issue-67945-1.rs +ui/const-generics/issues/issue-67945-2.rs +ui/const-generics/issues/issue-67945-3.rs +ui/const-generics/issues/issue-67945-4.rs +ui/const-generics/issues/issue-68104-print-stack-overflow.rs +ui/const-generics/issues/issue-68366.rs +ui/const-generics/issues/issue-68596.rs +ui/const-generics/issues/issue-68615-adt.rs +ui/const-generics/issues/issue-68615-array.rs +ui/const-generics/issues/issue-69654-run-pass.rs +ui/const-generics/issues/issue-70125-1.rs +ui/const-generics/issues/issue-70125-2.rs +ui/const-generics/issues/issue-70167.rs +ui/const-generics/issues/issue-70180-1-stalled_on.rs +ui/const-generics/issues/issue-70180-2-stalled_on.rs +ui/const-generics/issues/issue-70225.rs +ui/const-generics/issues/issue-70273-assoc-fn.rs +ui/const-generics/issues/issue-71169.rs +ui/const-generics/issues/issue-71202.rs +ui/const-generics/issues/issue-71381.rs +ui/const-generics/issues/issue-71382.rs +ui/const-generics/issues/issue-71547.rs +ui/const-generics/issues/issue-71611.rs +ui/const-generics/issues/issue-71986.rs +ui/const-generics/issues/issue-72352.rs +ui/const-generics/issues/issue-72845.rs +ui/const-generics/issues/issue-73120.rs +ui/const-generics/issues/issue-73260.rs +ui/const-generics/issues/issue-73491.rs +ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs +ui/const-generics/issues/issue-74101.rs +ui/const-generics/issues/issue-74255.rs +ui/const-generics/issues/issue-74906.rs +ui/const-generics/issues/issue-74950.rs +ui/const-generics/issues/issue-75047.rs +ui/const-generics/issues/issue-75299.rs +ui/const-generics/issues/issue-76701-ty-param-in-const.rs +ui/const-generics/issues/issue-79674.rs +ui/const-generics/issues/issue-80062.rs +ui/const-generics/issues/issue-80375.rs +ui/const-generics/issues/issue-82956.rs +ui/const-generics/issues/issue-83249.rs +ui/const-generics/issues/issue-83288.rs +ui/const-generics/issues/issue-83466.rs +ui/const-generics/issues/issue-83765.rs +ui/const-generics/issues/issue-84659.rs +ui/const-generics/issues/issue-85031-2.rs +ui/const-generics/issues/issue-86033.rs +ui/const-generics/issues/issue-86530.rs +ui/const-generics/issues/issue-86535-2.rs +ui/const-generics/issues/issue-86535.rs +ui/const-generics/issues/issue-86820.rs +ui/const-generics/issues/issue-87076.rs +ui/const-generics/issues/issue-87470.rs +ui/const-generics/issues/issue-87493.rs +ui/const-generics/issues/issue-87964.rs +ui/const-generics/issues/issue-88119.rs +ui/const-generics/issues/issue-88468.rs +ui/const-generics/issues/issue-88997.rs +ui/const-generics/issues/issue-89146.rs +ui/const-generics/issues/issue-89304.rs +ui/const-generics/issues/issue-89320.rs +ui/const-generics/issues/issue-89334.rs +ui/const-generics/issues/issue-90318.rs +ui/const-generics/issues/issue-90364.rs +ui/const-generics/issues/issue-90455.rs +ui/const-generics/issues/issue-92186.rs +ui/const-generics/issues/issue-96654.rs +ui/const-generics/issues/issue-97278.rs +ui/const-generics/issues/issue-97634.rs +ui/const-generics/issues/issue-98629.rs +ui/const-generics/issues/issue-99641.rs +ui/const-generics/parser-error-recovery/issue-89013-no-assoc.rs +ui/const-generics/parser-error-recovery/issue-89013-no-kw.rs +ui/const-generics/parser-error-recovery/issue-89013-type.rs +ui/const-generics/parser-error-recovery/issue-89013.rs +ui/const-generics/type-dependent/issue-61936.rs +ui/const-generics/type-dependent/issue-63695.rs +ui/const-generics/type-dependent/issue-67144-1.rs +ui/const-generics/type-dependent/issue-67144-2.rs +ui/const-generics/type-dependent/issue-69816.rs +ui/const-generics/type-dependent/issue-70217.rs +ui/const-generics/type-dependent/issue-70507.rs +ui/const-generics/type-dependent/issue-70586.rs +ui/const-generics/type-dependent/issue-71348.rs +ui/const-generics/type-dependent/issue-71382.rs +ui/const-generics/type-dependent/issue-71805.rs +ui/const-generics/type-dependent/issue-73730.rs +ui/const_prop/issue-102553.rs +ui/const_prop/issue-86351.rs +ui/consts/auxiliary/issue-17718-aux.rs +ui/consts/auxiliary/issue-63226.rs +ui/consts/const-eval/issue-100878.rs +ui/consts/const-eval/issue-104390.rs +ui/consts/const-eval/issue-114994-fail.rs +ui/consts/const-eval/issue-114994.rs +ui/consts/const-eval/issue-43197.rs +ui/consts/const-eval/issue-44578.rs +ui/consts/const-eval/issue-47971.rs +ui/consts/const-eval/issue-49296.rs +ui/consts/const-eval/issue-50706.rs +ui/consts/const-eval/issue-50814-2.rs +ui/consts/const-eval/issue-50814.rs +ui/consts/const-eval/issue-51300.rs +ui/consts/const-eval/issue-52475.rs +ui/consts/const-eval/issue-53157.rs +ui/consts/const-eval/issue-53401.rs +ui/consts/const-eval/issue-55541.rs +ui/consts/const-eval/issue-64908.rs +ui/consts/const-eval/issue-64970.rs +ui/consts/const-eval/issue-65394.rs +ui/consts/const-eval/issue-70723.rs +ui/consts/const-eval/issue-70804-fn-subtyping.rs +ui/consts/const-eval/issue-84957-const-str-as-bytes.rs +ui/consts/const-eval/issue-85155.rs +ui/consts/const-eval/issue-85907.rs +ui/consts/const-eval/issue-91827-extern-types-field-offset.rs +ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs +ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs +ui/consts/const-mut-refs/issue-76510.rs +ui/consts/const_in_pattern/issue-34784-match-on-non-int-raw-ptr.rs +ui/consts/const_in_pattern/issue-44333.rs +ui/consts/const_in_pattern/issue-53708.rs +ui/consts/const_in_pattern/issue-62614.rs +ui/consts/const_in_pattern/issue-65466.rs +ui/consts/const_in_pattern/issue-73431.rs +ui/consts/control-flow/issue-46843.rs +ui/consts/control-flow/issue-50577.rs +ui/consts/extra-const-ub/issue-100771.rs +ui/consts/extra-const-ub/issue-101034.rs +ui/consts/issue-102117.rs +ui/consts/issue-103790.rs +ui/consts/issue-104155.rs +ui/consts/issue-104396.rs +ui/consts/issue-104609.rs +ui/consts/issue-104768.rs +ui/consts/issue-105536-const-val-roundtrip-ptr-eq.rs +ui/consts/issue-116186.rs +ui/consts/issue-13837.rs +ui/consts/issue-13902.rs +ui/consts/issue-16538.rs +ui/consts/issue-17074.rs +ui/consts/issue-17458.rs +ui/consts/issue-17718-borrow-interior.rs +ui/consts/issue-17718-const-bad-values.rs +ui/consts/issue-17718-const-borrow.rs +ui/consts/issue-17718-constants-not-static.rs +ui/consts/issue-17718-references.rs +ui/consts/issue-17718.rs +ui/consts/issue-17756.rs +ui/consts/issue-18294.rs +ui/consts/issue-19244.rs +ui/consts/issue-21562.rs +ui/consts/issue-21721.rs +ui/consts/issue-23833.rs +ui/consts/issue-23968-const-not-overflow.rs +ui/consts/issue-25826.rs +ui/consts/issue-27890.rs +ui/consts/issue-28113.rs +ui/consts/issue-28822.rs +ui/consts/issue-29798.rs +ui/consts/issue-29914-2.rs +ui/consts/issue-29914-3.rs +ui/consts/issue-29914.rs +ui/consts/issue-29927-1.rs +ui/consts/issue-29927.rs +ui/consts/issue-32829-2.rs +ui/consts/issue-32829.rs +ui/consts/issue-33537.rs +ui/consts/issue-33903.rs +ui/consts/issue-3521.rs +ui/consts/issue-36163.rs +ui/consts/issue-37222.rs +ui/consts/issue-37550-1.rs +ui/consts/issue-37550.rs +ui/consts/issue-37991.rs +ui/consts/issue-39161-bogus-error.rs +ui/consts/issue-39974.rs +ui/consts/issue-43105.rs +ui/consts/issue-44255.rs +ui/consts/issue-44415.rs +ui/consts/issue-46553.rs +ui/consts/issue-47789.rs +ui/consts/issue-50439.rs +ui/consts/issue-52023-array-size-pointer-cast.rs +ui/consts/issue-52060.rs +ui/consts/issue-54224.rs +ui/consts/issue-54348.rs +ui/consts/issue-54387.rs +ui/consts/issue-54582.rs +ui/consts/issue-54954.rs +ui/consts/issue-56164.rs +ui/consts/issue-58435-ice-with-assoc-const.rs +ui/consts/issue-62045.rs +ui/consts/issue-63226.rs +ui/consts/issue-63952.rs +ui/consts/issue-64059.rs +ui/consts/issue-64506.rs +ui/consts/issue-64662.rs +ui/consts/issue-65348.rs +ui/consts/issue-66342.rs +ui/consts/issue-66345.rs +ui/consts/issue-66397.rs +ui/consts/issue-66693-panic-in-array-len.rs +ui/consts/issue-66693.rs +ui/consts/issue-66787.rs +ui/consts/issue-67529.rs +ui/consts/issue-67640.rs +ui/consts/issue-67641.rs +ui/consts/issue-67696-const-prop-ice.rs +ui/consts/issue-67862.rs +ui/consts/issue-68264-overflow.rs +ui/consts/issue-68542-closure-in-array-len.rs +ui/consts/issue-68684.rs +ui/consts/issue-69191-ice-on-uninhabited-enum-field.rs +ui/consts/issue-69310-array-size-lit-wrong-ty.rs +ui/consts/issue-69312.rs +ui/consts/issue-69488.rs +ui/consts/issue-69532.rs +ui/consts/issue-6991.rs +ui/consts/issue-70773-mir-typeck-lt-norm.rs +ui/consts/issue-70942-trait-vs-impl-mismatch.rs +ui/consts/issue-73976-monomorphic.rs +ui/consts/issue-73976-polymorphic.rs +ui/consts/issue-76064.rs +ui/consts/issue-77062-large-zst-array.rs +ui/consts/issue-78655.rs +ui/consts/issue-79137-monomorphic.rs +ui/consts/issue-79137-toogeneric.rs +ui/consts/issue-79152-const-array-index.rs +ui/consts/issue-79690.rs +ui/consts/issue-87046.rs +ui/consts/issue-88071.rs +ui/consts/issue-88649.rs +ui/consts/issue-89088.rs +ui/consts/issue-90762.rs +ui/consts/issue-90870.rs +ui/consts/issue-90878-2.rs +ui/consts/issue-90878-3.rs +ui/consts/issue-90878.rs +ui/consts/issue-91434.rs +ui/consts/issue-91560.rs +ui/consts/issue-94371.rs +ui/consts/issue-94675.rs +ui/consts/issue-96169.rs +ui/coroutine/issue-102645.rs +ui/coroutine/issue-105084.rs +ui/coroutine/issue-110929-coroutine-conflict-error-ice.rs +ui/coroutine/issue-113279.rs +ui/coroutine/issue-44197.rs +ui/coroutine/issue-45729-unsafe-in-coroutine.rs +ui/coroutine/issue-48048.rs +ui/coroutine/issue-52304.rs +ui/coroutine/issue-52398.rs +ui/coroutine/issue-53548-1.rs +ui/coroutine/issue-53548.rs +ui/coroutine/issue-57017.rs +ui/coroutine/issue-57084.rs +ui/coroutine/issue-57478.rs +ui/coroutine/issue-58888.rs +ui/coroutine/issue-61442-stmt-expr-with-drop.rs +ui/coroutine/issue-62506-two_awaits.rs +ui/coroutine/issue-64620-yield-array-element.rs +ui/coroutine/issue-68112.rs +ui/coroutine/issue-69017.rs +ui/coroutine/issue-69039.rs +ui/coroutine/issue-87142.rs +ui/coroutine/issue-88653.rs +ui/coroutine/issue-91477.rs +ui/coroutine/issue-93161.rs +ui/cross-crate/issue-64872/issue-64872.rs +ui/cycle-trait/issue-12511.rs +ui/debuginfo/issue-105386-debuginfo-ub.rs +ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs +ui/deprecation/issue-84637-deprecated-associated-function.rs +ui/derived-errors/issue-30580.rs +ui/derived-errors/issue-31997-1.rs +ui/derived-errors/issue-31997.rs +ui/derives/issue-36617.rs +ui/derives/issue-43023.rs +ui/derives/issue-91492.rs +ui/derives/issue-91550.rs +ui/derives/issue-97343.rs +ui/deriving/issue-103157.rs +ui/deriving/issue-15689-1.rs +ui/deriving/issue-15689-2.rs +ui/deriving/issue-18738.rs +ui/deriving/issue-19358.rs +ui/deriving/issue-3935.rs +ui/deriving/issue-58319.rs +ui/deriving/issue-6341.rs +ui/deriving/issue-89188-gat-hrtb.rs +ui/did_you_mean/issue-103909.rs +ui/did_you_mean/issue-105225-named-args.rs +ui/did_you_mean/issue-105225.rs +ui/did_you_mean/issue-114112.rs +ui/did_you_mean/issue-21659-show-relevant-trait-impls-1.rs +ui/did_you_mean/issue-21659-show-relevant-trait-impls-2.rs +ui/did_you_mean/issue-31424.rs +ui/did_you_mean/issue-34126.rs +ui/did_you_mean/issue-34337.rs +ui/did_you_mean/issue-35937.rs +ui/did_you_mean/issue-36798.rs +ui/did_you_mean/issue-36798_unknown_field.rs +ui/did_you_mean/issue-37139.rs +ui/did_you_mean/issue-38054-do-not-show-unresolved-names.rs +ui/did_you_mean/issue-38147-1.rs +ui/did_you_mean/issue-38147-2.rs +ui/did_you_mean/issue-38147-3.rs +ui/did_you_mean/issue-38147-4.rs +ui/did_you_mean/issue-39544.rs +ui/did_you_mean/issue-39802-show-5-trait-impls.rs +ui/did_you_mean/issue-40006.rs +ui/did_you_mean/issue-40396.rs +ui/did_you_mean/issue-40823.rs +ui/did_you_mean/issue-41679-tilde-bitwise-negation-attempt.rs +ui/did_you_mean/issue-42599_available_fields_note.rs +ui/did_you_mean/issue-42764.rs +ui/did_you_mean/issue-43871-enum-instead-of-variant.rs +ui/did_you_mean/issue-46718-struct-pattern-dotdotdot.rs +ui/did_you_mean/issue-46836-identifier-not-instead-of-negation.rs +ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.rs +ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.rs +ui/did_you_mean/issue-53280-expected-float-found-integer-literal.rs +ui/did_you_mean/issue-54109-and_instead_of_ampersands.rs +ui/did_you_mean/issue-54109-without-witness.rs +ui/did_you_mean/issue-56028-there-is-an-enum-variant.rs +ui/did_you_mean/issue-87830-try-brackets-for-arrays.rs +ui/drop/auxiliary/issue-10028.rs +ui/drop/issue-100276.rs +ui/drop/issue-10028.rs +ui/drop/issue-103107.rs +ui/drop/issue-110682.rs +ui/drop/issue-17718-const-destructors.rs +ui/drop/issue-21486.rs +ui/drop/issue-23338-ensure-param-drop-order.rs +ui/drop/issue-23611-enum-swap-in-drop.rs +ui/drop/issue-2734.rs +ui/drop/issue-2735-2.rs +ui/drop/issue-2735-3.rs +ui/drop/issue-2735.rs +ui/drop/issue-30018-nopanic.rs +ui/drop/issue-35546.rs +ui/drop/issue-48962.rs +ui/drop/issue-90752-raw-ptr-shenanigans.rs +ui/drop/issue-90752.rs +ui/drop/issue-979.rs +ui/dropck/issue-24805-dropck-itemless.rs +ui/dropck/issue-28498-ugeh-with-lifetime-param.rs +ui/dropck/issue-28498-ugeh-with-passed-to-fn.rs +ui/dropck/issue-28498-ugeh-with-trait-bound.rs +ui/dropck/issue-29844.rs +ui/dropck/issue-34053.rs +ui/dropck/issue-38868.rs +ui/dropck/issue-54943-1.rs +ui/dropck/issue-54943-2.rs +ui/dst/issue-113447.rs +ui/dst/issue-90528-unsizing-not-suggestion-110063.rs +ui/dst/issue-90528-unsizing-suggestion-1.rs +ui/dst/issue-90528-unsizing-suggestion-2.rs +ui/dst/issue-90528-unsizing-suggestion-3.rs +ui/dst/issue-90528-unsizing-suggestion-4.rs +ui/dyn-keyword/issue-5153.rs +ui/dyn-keyword/issue-56327-dyn-trait-in-macro-is-okay.rs +ui/dyn-star/issue-102430.rs +ui/empty/issue-37026.rs +ui/entry-point/issue-118772.rs +ui/enum-discriminant/auxiliary/issue-41394.rs +ui/enum-discriminant/issue-104519.rs +ui/enum-discriminant/issue-41394-rpass.rs +ui/enum-discriminant/issue-41394.rs +ui/enum-discriminant/issue-43398.rs +ui/enum-discriminant/issue-46519.rs +ui/enum-discriminant/issue-50689.rs +ui/enum-discriminant/issue-51582.rs +ui/enum-discriminant/issue-61696.rs +ui/enum-discriminant/issue-70453-generics-in-discr-ice-2.rs +ui/enum-discriminant/issue-70453-generics-in-discr-ice.rs +ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +ui/enum-discriminant/issue-70509-partial_eq.rs +ui/enum-discriminant/issue-72554.rs +ui/enum-discriminant/issue-90038.rs +ui/enum/issue-1821.rs +ui/enum/issue-42747.rs +ui/enum/issue-67945-1.rs +ui/enum/issue-67945-2.rs +ui/error-codes/e0119/auxiliary/issue-23563-a.rs +ui/error-codes/e0119/issue-23563.rs +ui/error-codes/e0119/issue-27403.rs +ui/error-codes/e0119/issue-28981.rs +ui/errors/issue-104621-extern-bad-file.rs +ui/errors/issue-104621-extern-not-file.rs +ui/errors/issue-89280-emitter-overflow-splice-lines.rs +ui/errors/issue-99572-impl-trait-on-pointer.rs +ui/expr/if/issue-4201.rs +ui/extern/auxiliary/issue-80074-macro-2.rs +ui/extern/auxiliary/issue-80074-macro.rs +ui/extern/issue-10025.rs +ui/extern/issue-10763.rs +ui/extern/issue-10764-rpass.rs +ui/extern/issue-112363-extern-item-where-clauses-debug-ice.rs +ui/extern/issue-116203.rs +ui/extern/issue-1251.rs +ui/extern/issue-13655.rs +ui/extern/issue-16250.rs +ui/extern/issue-18576.rs +ui/extern/issue-18819.rs +ui/extern/issue-28324.rs +ui/extern/issue-36122-accessing-externed-dst.rs +ui/extern/issue-47725.rs +ui/extern/issue-64655-allow-unwind-when-calling-panic-directly.rs +ui/extern/issue-64655-extern-rust-must-allow-unwind.rs +ui/extern/issue-80074.rs +ui/extern/issue-95829.rs +ui/feature-gates/issue-43106-gating-of-bench.rs +ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs +ui/feature-gates/issue-43106-gating-of-deprecated.rs +ui/feature-gates/issue-43106-gating-of-derive-2.rs +ui/feature-gates/issue-43106-gating-of-derive.rs +ui/feature-gates/issue-43106-gating-of-macro_escape.rs +ui/feature-gates/issue-43106-gating-of-macro_use.rs +ui/feature-gates/issue-43106-gating-of-proc_macro_derive.rs +ui/feature-gates/issue-43106-gating-of-stable.rs +ui/feature-gates/issue-43106-gating-of-test.rs +ui/feature-gates/issue-43106-gating-of-unstable.rs +ui/feature-gates/issue-49983-see-issue-0.rs +ui/fmt/issue-103826.rs +ui/fmt/issue-104142.rs +ui/fmt/issue-23781.rs +ui/fmt/issue-75307.rs +ui/fmt/issue-86085.rs +ui/fmt/issue-89173.rs +ui/fmt/issue-91556.rs +ui/fn/issue-1451.rs +ui/fn/issue-1900.rs +ui/fn/issue-3044.rs +ui/fn/issue-3099.rs +ui/fn/issue-3904.rs +ui/fn/issue-39259.rs +ui/fn/issue-80179.rs +ui/for-loop-while/issue-1257.rs +ui/for-loop-while/issue-2216.rs +ui/for-loop-while/issue-51345.rs +ui/for-loop-while/issue-69841.rs +ui/for/issue-20605.rs +ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs +ui/foreign/issue-91370-foreign-fn-block-impl.rs +ui/foreign/issue-99276-same-type-lifetimes.rs +ui/function-pointer/issue-102289.rs +ui/functions-closures/closure-expected-type/issue-38714.rs +ui/generic-associated-types/bugs/issue-100013.rs +ui/generic-associated-types/bugs/issue-80626.rs +ui/generic-associated-types/bugs/issue-87735.rs +ui/generic-associated-types/bugs/issue-87755.rs +ui/generic-associated-types/bugs/issue-87803.rs +ui/generic-associated-types/bugs/issue-88382.rs +ui/generic-associated-types/bugs/issue-88460.rs +ui/generic-associated-types/bugs/issue-88526.rs +ui/generic-associated-types/bugs/issue-91762.rs +ui/generic-associated-types/issue-101020.rs +ui/generic-associated-types/issue-102114.rs +ui/generic-associated-types/issue-102333.rs +ui/generic-associated-types/issue-102335-gat.rs +ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs +ui/generic-associated-types/issue-47206-where-clause.rs +ui/generic-associated-types/issue-58694-parameter-out-of-range.rs +ui/generic-associated-types/issue-62326-parameter-out-of-range.rs +ui/generic-associated-types/issue-67424.rs +ui/generic-associated-types/issue-67510-pass.rs +ui/generic-associated-types/issue-67510.rs +ui/generic-associated-types/issue-68641-check-gat-bounds.rs +ui/generic-associated-types/issue-68642-broken-llvm-ir.rs +ui/generic-associated-types/issue-68643-broken-mir.rs +ui/generic-associated-types/issue-68644-codegen-selection.rs +ui/generic-associated-types/issue-68645-codegen-fulfillment.rs +ui/generic-associated-types/issue-68648-1.rs +ui/generic-associated-types/issue-68648-2.rs +ui/generic-associated-types/issue-68649-pass.rs +ui/generic-associated-types/issue-68653.rs +ui/generic-associated-types/issue-68656-unsized-values.rs +ui/generic-associated-types/issue-70303.rs +ui/generic-associated-types/issue-70304.rs +ui/generic-associated-types/issue-71176.rs +ui/generic-associated-types/issue-74684-1.rs +ui/generic-associated-types/issue-74684-2.rs +ui/generic-associated-types/issue-74816.rs +ui/generic-associated-types/issue-74824.rs +ui/generic-associated-types/issue-76407.rs +ui/generic-associated-types/issue-76535.rs +ui/generic-associated-types/issue-76826.rs +ui/generic-associated-types/issue-78113-lifetime-mismatch-dyn-trait-box.rs +ui/generic-associated-types/issue-78671.rs +ui/generic-associated-types/issue-79422.rs +ui/generic-associated-types/issue-79636-1.rs +ui/generic-associated-types/issue-79636-2.rs +ui/generic-associated-types/issue-80433-reduced.rs +ui/generic-associated-types/issue-80433.rs +ui/generic-associated-types/issue-81487.rs +ui/generic-associated-types/issue-81712-cyclic-traits.rs +ui/generic-associated-types/issue-81862.rs +ui/generic-associated-types/issue-84931.rs +ui/generic-associated-types/issue-85921.rs +ui/generic-associated-types/issue-86218-2.rs +ui/generic-associated-types/issue-86218.rs +ui/generic-associated-types/issue-86483.rs +ui/generic-associated-types/issue-86787.rs +ui/generic-associated-types/issue-87258_a.rs +ui/generic-associated-types/issue-87258_b.rs +ui/generic-associated-types/issue-87429-2.rs +ui/generic-associated-types/issue-87429-associated-type-default.rs +ui/generic-associated-types/issue-87429-specialization.rs +ui/generic-associated-types/issue-87429.rs +ui/generic-associated-types/issue-87748.rs +ui/generic-associated-types/issue-87750.rs +ui/generic-associated-types/issue-88287.rs +ui/generic-associated-types/issue-88360.rs +ui/generic-associated-types/issue-88405.rs +ui/generic-associated-types/issue-88459.rs +ui/generic-associated-types/issue-88595.rs +ui/generic-associated-types/issue-89008.rs +ui/generic-associated-types/issue-89352.rs +ui/generic-associated-types/issue-90014-tait.rs +ui/generic-associated-types/issue-90014-tait2.rs +ui/generic-associated-types/issue-90014.rs +ui/generic-associated-types/issue-90729.rs +ui/generic-associated-types/issue-91139.rs +ui/generic-associated-types/issue-91883.rs +ui/generic-associated-types/issue-92033.rs +ui/generic-associated-types/issue-92096.rs +ui/generic-associated-types/issue-92280.rs +ui/generic-associated-types/issue-92954.rs +ui/generic-associated-types/issue-93141.rs +ui/generic-associated-types/issue-93262.rs +ui/generic-associated-types/issue-93341.rs +ui/generic-associated-types/issue-93342.rs +ui/generic-associated-types/issue-93874.rs +ui/generic-associated-types/issue-95305.rs +ui/generics/issue-106694.rs +ui/generics/issue-1112.rs +ui/generics/issue-2936.rs +ui/generics/issue-32498.rs +ui/generics/issue-333.rs +ui/generics/issue-59508-1.rs +ui/generics/issue-59508.rs +ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.rs +ui/generics/issue-61631-default-type-param-cannot-reference-self.rs +ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs +ui/generics/issue-79605.rs +ui/generics/issue-80512-param-reordering-with-defaults.rs +ui/generics/issue-83556.rs +ui/generics/issue-94432-garbage-ice.rs +ui/generics/issue-94923.rs +ui/generics/issue-95208-ignore-qself.rs +ui/generics/issue-95208.rs +ui/generics/issue-98432.rs +ui/higher-ranked/trait-bounds/issue-100689.rs +ui/higher-ranked/trait-bounds/issue-102899.rs +ui/higher-ranked/trait-bounds/issue-36139-normalize-closure-sig.rs +ui/higher-ranked/trait-bounds/issue-39292.rs +ui/higher-ranked/trait-bounds/issue-42114.rs +ui/higher-ranked/trait-bounds/issue-43623.rs +ui/higher-ranked/trait-bounds/issue-46989.rs +ui/higher-ranked/trait-bounds/issue-57639.rs +ui/higher-ranked/trait-bounds/issue-58451.rs +ui/higher-ranked/trait-bounds/issue-59311.rs +ui/higher-ranked/trait-bounds/issue-60283.rs +ui/higher-ranked/trait-bounds/issue-62203-hrtb-ice.rs +ui/higher-ranked/trait-bounds/issue-88446.rs +ui/higher-ranked/trait-bounds/issue-88586-hr-self-outlives-in-trait-def.rs +ui/higher-ranked/trait-bounds/issue-90177.rs +ui/higher-ranked/trait-bounds/issue-95034.rs +ui/higher-ranked/trait-bounds/issue-95230.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-44005.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-56556.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-1.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-2.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-3.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-4.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-5.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-62529-6.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-70120.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-71955.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-74261.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-76956.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80706.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-80956.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-81809.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-85455.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89118.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-89436.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90612.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90638.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90875.rs +ui/higher-ranked/trait-bounds/normalize-under-binder/issue-90950.rs +ui/hygiene/issue-15221.rs +ui/hygiene/issue-29746.rs +ui/hygiene/issue-32922.rs +ui/hygiene/issue-40847.rs +ui/hygiene/issue-44128.rs +ui/hygiene/issue-47311.rs +ui/hygiene/issue-47312.rs +ui/hygiene/issue-61574-const-parameters.rs +ui/hygiene/issue-77523-def-site-async-await.rs +ui/impl-trait/explicit-generic-args-with-impl-trait/issue-87718.rs +ui/impl-trait/in-trait/issue-102140.rs +ui/impl-trait/in-trait/issue-102301.rs +ui/impl-trait/in-trait/issue-102571.rs +ui/impl-trait/issue-100075-2.rs +ui/impl-trait/issue-100075.rs +ui/impl-trait/issue-100187.rs +ui/impl-trait/issue-102605.rs +ui/impl-trait/issue-103181-1.rs +ui/impl-trait/issue-103181-2.rs +ui/impl-trait/issue-103599.rs +ui/impl-trait/issue-108591.rs +ui/impl-trait/issue-108592.rs +ui/impl-trait/issue-35668.rs +ui/impl-trait/issue-36792.rs +ui/impl-trait/issue-46959.rs +ui/impl-trait/issue-49556.rs +ui/impl-trait/issue-49579.rs +ui/impl-trait/issue-49685.rs +ui/impl-trait/issue-51185.rs +ui/impl-trait/issue-54966.rs +ui/impl-trait/issue-55872-1.rs +ui/impl-trait/issue-55872-2.rs +ui/impl-trait/issue-55872-3.rs +ui/impl-trait/issue-55872.rs +ui/impl-trait/issue-56445.rs +ui/impl-trait/issue-68532.rs +ui/impl-trait/issue-72911.rs +ui/impl-trait/issue-87450.rs +ui/impl-trait/issue-99073-2.rs +ui/impl-trait/issue-99073.rs +ui/impl-trait/issue-99642-2.rs +ui/impl-trait/issue-99642.rs +ui/impl-trait/issue-99914.rs +ui/impl-trait/issues/issue-104815.rs +ui/impl-trait/issues/issue-105826.rs +ui/impl-trait/issues/issue-21659-show-relevant-trait-impls-3.rs +ui/impl-trait/issues/issue-42479.rs +ui/impl-trait/issues/issue-49376.rs +ui/impl-trait/issues/issue-52128.rs +ui/impl-trait/issues/issue-53457.rs +ui/impl-trait/issues/issue-54600.rs +ui/impl-trait/issues/issue-54840.rs +ui/impl-trait/issues/issue-54895.rs +ui/impl-trait/issues/issue-55608-captures-empty-region.rs +ui/impl-trait/issues/issue-57464-unexpected-regions.rs +ui/impl-trait/issues/issue-57979-deeply-nested-impl-trait-in-assoc-proj.rs +ui/impl-trait/issues/issue-57979-impl-trait-in-path.rs +ui/impl-trait/issues/issue-57979-nested-impl-trait-in-assoc-proj.rs +ui/impl-trait/issues/issue-58504.rs +ui/impl-trait/issues/issue-58956.rs +ui/impl-trait/issues/issue-62742.rs +ui/impl-trait/issues/issue-65581.rs +ui/impl-trait/issues/issue-67830.rs +ui/impl-trait/issues/issue-70877.rs +ui/impl-trait/issues/issue-70971.rs +ui/impl-trait/issues/issue-74282.rs +ui/impl-trait/issues/issue-77987.rs +ui/impl-trait/issues/issue-78722-2.rs +ui/impl-trait/issues/issue-78722.rs +ui/impl-trait/issues/issue-79099.rs +ui/impl-trait/issues/issue-82139.rs +ui/impl-trait/issues/issue-83919.rs +ui/impl-trait/issues/issue-83929-impl-trait-in-generic-default.rs +ui/impl-trait/issues/issue-84073.rs +ui/impl-trait/issues/issue-84919.rs +ui/impl-trait/issues/issue-86201.rs +ui/impl-trait/issues/issue-86642.rs +ui/impl-trait/issues/issue-86719.rs +ui/impl-trait/issues/issue-86800.rs +ui/impl-trait/issues/issue-87295.rs +ui/impl-trait/issues/issue-87340.rs +ui/impl-trait/issues/issue-88236-2.rs +ui/impl-trait/issues/issue-88236.rs +ui/impl-trait/issues/issue-89312.rs +ui/impl-trait/issues/issue-92305.rs +ui/impl-trait/issues/issue-93788.rs +ui/impl-trait/issues/issue-99348-impl-compatibility.rs +ui/implied-bounds/issue-100690.rs +ui/implied-bounds/issue-101951.rs +ui/implied-bounds/issue-110161.rs +ui/imports/auxiliary/issue-114682-2-extern.rs +ui/imports/auxiliary/issue-114682-3-extern.rs +ui/imports/auxiliary/issue-114682-4-extern.rs +ui/imports/auxiliary/issue-114682-5-extern-1.rs +ui/imports/auxiliary/issue-114682-5-extern-2.rs +ui/imports/auxiliary/issue-114682-6-extern.rs +ui/imports/auxiliary/issue-119369-extern.rs +ui/imports/auxiliary/issue-36881-aux.rs +ui/imports/auxiliary/issue-52891.rs +ui/imports/auxiliary/issue-55811.rs +ui/imports/auxiliary/issue-56125.rs +ui/imports/auxiliary/issue-59764.rs +ui/imports/auxiliary/issue-85992-extern-1.rs +ui/imports/auxiliary/issue-85992-extern-2.rs +ui/imports/issue-109148.rs +ui/imports/issue-109343.rs +ui/imports/issue-113953.rs +ui/imports/issue-114682-1.rs +ui/imports/issue-114682-2.rs +ui/imports/issue-114682-3.rs +ui/imports/issue-114682-4.rs +ui/imports/issue-114682-5.rs +ui/imports/issue-114682-6.rs +ui/imports/issue-119369.rs +ui/imports/issue-13404.rs +ui/imports/issue-1697.rs +ui/imports/issue-18083.rs +ui/imports/issue-19498.rs +ui/imports/issue-24081.rs +ui/imports/issue-24883.rs +ui/imports/issue-25396.rs +ui/imports/issue-26873-multifile/issue-26873-multifile.rs +ui/imports/issue-26873-multifile/issue-26873-onefile.rs +ui/imports/issue-26886.rs +ui/imports/issue-26930.rs +ui/imports/issue-28134.rs +ui/imports/issue-28388-1.rs +ui/imports/issue-28388-2.rs +ui/imports/issue-2937.rs +ui/imports/issue-30560.rs +ui/imports/issue-31212.rs +ui/imports/issue-32119.rs +ui/imports/issue-32222.rs +ui/imports/issue-32354-suggest-import-rename.rs +ui/imports/issue-32833.rs +ui/imports/issue-33464.rs +ui/imports/issue-36881.rs +ui/imports/issue-37887.rs +ui/imports/issue-38293.rs +ui/imports/issue-4366-2.rs +ui/imports/issue-4366.rs +ui/imports/issue-45799-bad-extern-crate-rename-suggestion-formatting.rs +ui/imports/issue-45829/auxiliary/issue-45829-a.rs +ui/imports/issue-45829/auxiliary/issue-45829-b.rs +ui/imports/issue-45829/issue-45829.rs +ui/imports/issue-47623.rs +ui/imports/issue-4865-1.rs +ui/imports/issue-4865-2.rs +ui/imports/issue-4865-3.rs +ui/imports/issue-52891.rs +ui/imports/issue-53140.rs +ui/imports/issue-53269.rs +ui/imports/issue-53512.rs +ui/imports/issue-53565.rs +ui/imports/issue-55457.rs +ui/imports/issue-55811.rs +ui/imports/issue-55884-1.rs +ui/imports/issue-55884-2.rs +ui/imports/issue-56125.rs +ui/imports/issue-56263.rs +ui/imports/issue-57015.rs +ui/imports/issue-57539.rs +ui/imports/issue-59764.rs +ui/imports/issue-62767.rs +ui/imports/issue-68103.rs +ui/imports/issue-81413.rs +ui/imports/issue-8208.rs +ui/imports/issue-85992.rs +ui/imports/issue-8640.rs +ui/imports/issue-99695-b.rs +ui/imports/issue-99695.rs +ui/inference/issue-103587.rs +ui/inference/issue-104649.rs +ui/inference/issue-107090.rs +ui/inference/issue-113354.rs +ui/inference/issue-12028.rs +ui/inference/issue-28935.rs +ui/inference/issue-36053.rs +ui/inference/issue-3743.rs +ui/inference/issue-70082.rs +ui/inference/issue-70703.rs +ui/inference/issue-71309.rs +ui/inference/issue-71584.rs +ui/inference/issue-71732.rs +ui/inference/issue-72616.rs +ui/inference/issue-72690.rs +ui/inference/issue-80409.rs +ui/inference/issue-80816.rs +ui/inference/issue-81522.rs +ui/inference/issue-83606.rs +ui/inference/issue-86094-suggest-add-return-to-coerce-ret-ty.rs +ui/inference/issue-86162-1.rs +ui/inference/issue-86162-2.rs +ui/inference/need_type_info/issue-103053.rs +ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs +ui/inference/need_type_info/issue-109905.rs +ui/inference/need_type_info/issue-113264-incorrect-impl-trait-in-path-suggestion.rs +ui/infinite/issue-41731-infinite-macro-print.rs +ui/infinite/issue-41731-infinite-macro-println.rs +ui/intrinsics/issue-28575.rs +ui/intrinsics/issue-84297-reifying-copy.rs +ui/invalid/issue-114435-layout-type-err.rs +ui/issue-11881.rs +ui/issue-13560.rs +ui/issue-15924.rs +ui/issue-16822.rs +ui/issue-18502.rs +ui/issue-24106.rs +ui/issue-76387-llvm-miscompile.rs +ui/issues-71798.rs +ui/issues/auxiliary/issue-111011.rs +ui/issues/auxiliary/issue-11224.rs +ui/issues/auxiliary/issue-11508.rs +ui/issues/auxiliary/issue-11529.rs +ui/issues/auxiliary/issue-11680.rs +ui/issues/auxiliary/issue-12612-1.rs +ui/issues/auxiliary/issue-12612-2.rs +ui/issues/auxiliary/issue-12660-aux.rs +ui/issues/auxiliary/issue-13507.rs +ui/issues/auxiliary/issue-13620-1.rs +ui/issues/auxiliary/issue-13620-2.rs +ui/issues/auxiliary/issue-14344-1.rs +ui/issues/auxiliary/issue-14344-2.rs +ui/issues/auxiliary/issue-14421.rs +ui/issues/auxiliary/issue-14422.rs +ui/issues/auxiliary/issue-15562.rs +ui/issues/auxiliary/issue-16643.rs +ui/issues/auxiliary/issue-16725.rs +ui/issues/auxiliary/issue-17662.rs +ui/issues/auxiliary/issue-18501.rs +ui/issues/auxiliary/issue-18514.rs +ui/issues/auxiliary/issue-18711.rs +ui/issues/auxiliary/issue-18913-1.rs +ui/issues/auxiliary/issue-18913-2.rs +ui/issues/auxiliary/issue-19293.rs +ui/issues/auxiliary/issue-19340-1.rs +ui/issues/auxiliary/issue-20389.rs +ui/issues/auxiliary/issue-21202.rs +ui/issues/auxiliary/issue-2170-lib.rs +ui/issues/auxiliary/issue-2316-a.rs +ui/issues/auxiliary/issue-2316-b.rs +ui/issues/auxiliary/issue-2380.rs +ui/issues/auxiliary/issue-2414-a.rs +ui/issues/auxiliary/issue-2414-b.rs +ui/issues/auxiliary/issue-2472-b.rs +ui/issues/auxiliary/issue-25185-1.rs +ui/issues/auxiliary/issue-25185-2.rs +ui/issues/auxiliary/issue-2526.rs +ui/issues/auxiliary/issue-25467.rs +ui/issues/auxiliary/issue-2631-a.rs +ui/issues/auxiliary/issue-2723-a.rs +ui/issues/auxiliary/issue-29265.rs +ui/issues/auxiliary/issue-29485.rs +ui/issues/auxiliary/issue-3012-1.rs +ui/issues/auxiliary/issue-30123-aux.rs +ui/issues/auxiliary/issue-3136-a.rs +ui/issues/auxiliary/issue-31702-1.rs +ui/issues/auxiliary/issue-31702-2.rs +ui/issues/auxiliary/issue-34796-aux.rs +ui/issues/auxiliary/issue-36954.rs +ui/issues/auxiliary/issue-38190.rs +ui/issues/auxiliary/issue-38226-aux.rs +ui/issues/auxiliary/issue-3979-traits.rs +ui/issues/auxiliary/issue-41053.rs +ui/issues/auxiliary/issue-41549.rs +ui/issues/auxiliary/issue-42007-s.rs +ui/issues/auxiliary/issue-4208-cc.rs +ui/issues/auxiliary/issue-4545.rs +ui/issues/auxiliary/issue-48984-aux.rs +ui/issues/auxiliary/issue-49544.rs +ui/issues/auxiliary/issue-51798.rs +ui/issues/auxiliary/issue-52489.rs +ui/issues/auxiliary/issue-5518.rs +ui/issues/auxiliary/issue-5521.rs +ui/issues/auxiliary/issue-56943.rs +ui/issues/auxiliary/issue-57271-lib.rs +ui/issues/auxiliary/issue-5844-aux.rs +ui/issues/auxiliary/issue-7178.rs +ui/issues/auxiliary/issue-73112.rs +ui/issues/auxiliary/issue-7899.rs +ui/issues/auxiliary/issue-8044.rs +ui/issues/auxiliary/issue-8259.rs +ui/issues/auxiliary/issue-8401.rs +ui/issues/auxiliary/issue-9123.rs +ui/issues/auxiliary/issue-9155.rs +ui/issues/auxiliary/issue-9188.rs +ui/issues/auxiliary/issue-9906.rs +ui/issues/auxiliary/issue-9968.rs +ui/issues/issue-10228.rs +ui/issues/issue-10291.rs +ui/issues/issue-102964.rs +ui/issues/issue-10396.rs +ui/issues/issue-10412.rs +ui/issues/issue-10436.rs +ui/issues/issue-10456.rs +ui/issues/issue-10465.rs +ui/issues/issue-10545.rs +ui/issues/issue-10638.rs +ui/issues/issue-10656.rs +ui/issues/issue-106755.rs +ui/issues/issue-10683.rs +ui/issues/issue-10718.rs +ui/issues/issue-10734.rs +ui/issues/issue-10764.rs +ui/issues/issue-10767.rs +ui/issues/issue-10802.rs +ui/issues/issue-10806.rs +ui/issues/issue-10853.rs +ui/issues/issue-10877.rs +ui/issues/issue-10902.rs +ui/issues/issue-11004.rs +ui/issues/issue-11047.rs +ui/issues/issue-11085.rs +ui/issues/issue-11192.rs +ui/issues/issue-11205.rs +ui/issues/issue-11224.rs +ui/issues/issue-11267.rs +ui/issues/issue-11374.rs +ui/issues/issue-11382.rs +ui/issues/issue-11384.rs +ui/issues/issue-11508.rs +ui/issues/issue-11529.rs +ui/issues/issue-11552.rs +ui/issues/issue-11592.rs +ui/issues/issue-11677.rs +ui/issues/issue-11680.rs +ui/issues/issue-11681.rs +ui/issues/issue-11692-1.rs +ui/issues/issue-11692-2.rs +ui/issues/issue-11709.rs +ui/issues/issue-11740.rs +ui/issues/issue-11771.rs +ui/issues/issue-11820.rs +ui/issues/issue-11844.rs +ui/issues/issue-11869.rs +ui/issues/issue-11958.rs +ui/issues/issue-12033.rs +ui/issues/issue-12041.rs +ui/issues/issue-12127.rs +ui/issues/issue-12187-1.rs +ui/issues/issue-12187-2.rs +ui/issues/issue-12285.rs +ui/issues/issue-12567.rs +ui/issues/issue-12612.rs +ui/issues/issue-12660.rs +ui/issues/issue-12677.rs +ui/issues/issue-12699.rs +ui/issues/issue-12729.rs +ui/issues/issue-12744.rs +ui/issues/issue-12860.rs +ui/issues/issue-12863.rs +ui/issues/issue-12909.rs +ui/issues/issue-12920.rs +ui/issues/issue-13027.rs +ui/issues/issue-13058.rs +ui/issues/issue-13105.rs +ui/issues/issue-13167.rs +ui/issues/issue-13202.rs +ui/issues/issue-13204.rs +ui/issues/issue-13214.rs +ui/issues/issue-13259-windows-tcb-trash.rs +ui/issues/issue-13264.rs +ui/issues/issue-13323.rs +ui/issues/issue-13359.rs +ui/issues/issue-13405.rs +ui/issues/issue-13407.rs +ui/issues/issue-13434.rs +ui/issues/issue-13446.rs +ui/issues/issue-13466.rs +ui/issues/issue-13482-2.rs +ui/issues/issue-13482.rs +ui/issues/issue-13497-2.rs +ui/issues/issue-13497.rs +ui/issues/issue-13507-2.rs +ui/issues/issue-13620.rs +ui/issues/issue-13665.rs +ui/issues/issue-13703.rs +ui/issues/issue-13763.rs +ui/issues/issue-13775.rs +ui/issues/issue-13808.rs +ui/issues/issue-13847.rs +ui/issues/issue-13867.rs +ui/issues/issue-14082.rs +ui/issues/issue-14091-2.rs +ui/issues/issue-14091.rs +ui/issues/issue-14092.rs +ui/issues/issue-14229.rs +ui/issues/issue-14254.rs +ui/issues/issue-14285.rs +ui/issues/issue-14308.rs +ui/issues/issue-14330.rs +ui/issues/issue-14344.rs +ui/issues/issue-14366.rs +ui/issues/issue-14382.rs +ui/issues/issue-14393.rs +ui/issues/issue-14399.rs +ui/issues/issue-14421.rs +ui/issues/issue-14422.rs +ui/issues/issue-14541.rs +ui/issues/issue-14721.rs +ui/issues/issue-14821.rs +ui/issues/issue-14845.rs +ui/issues/issue-14853.rs +ui/issues/issue-14865.rs +ui/issues/issue-14875.rs +ui/issues/issue-14901.rs +ui/issues/issue-14915.rs +ui/issues/issue-14919.rs +ui/issues/issue-14959.rs +ui/issues/issue-15034.rs +ui/issues/issue-15043.rs +ui/issues/issue-15063.rs +ui/issues/issue-15094.rs +ui/issues/issue-15104.rs +ui/issues/issue-15129-rpass.rs +ui/issues/issue-15167.rs +ui/issues/issue-15189.rs +ui/issues/issue-15207.rs +ui/issues/issue-15260.rs +ui/issues/issue-15381.rs +ui/issues/issue-15444.rs +ui/issues/issue-15523-big.rs +ui/issues/issue-15523.rs +ui/issues/issue-15562.rs +ui/issues/issue-15571.rs +ui/issues/issue-15673.rs +ui/issues/issue-15734.rs +ui/issues/issue-15735.rs +ui/issues/issue-15756.rs +ui/issues/issue-15763.rs +ui/issues/issue-15774.rs +ui/issues/issue-15783.rs +ui/issues/issue-15793.rs +ui/issues/issue-15858.rs +ui/issues/issue-15896.rs +ui/issues/issue-15965.rs +ui/issues/issue-16048.rs +ui/issues/issue-16149.rs +ui/issues/issue-16151.rs +ui/issues/issue-16256.rs +ui/issues/issue-16278.rs +ui/issues/issue-16401.rs +ui/issues/issue-16441.rs +ui/issues/issue-16452.rs +ui/issues/issue-16492.rs +ui/issues/issue-16530.rs +ui/issues/issue-16560.rs +ui/issues/issue-16562.rs +ui/issues/issue-16596.rs +ui/issues/issue-16643.rs +ui/issues/issue-16648.rs +ui/issues/issue-16668.rs +ui/issues/issue-16671.rs +ui/issues/issue-16683.rs +ui/issues/issue-16725.rs +ui/issues/issue-16739.rs +ui/issues/issue-16745.rs +ui/issues/issue-16774.rs +ui/issues/issue-16783.rs +ui/issues/issue-16819.rs +ui/issues/issue-16922-rpass.rs +ui/issues/issue-16939.rs +ui/issues/issue-16966.rs +ui/issues/issue-16994.rs +ui/issues/issue-17001.rs +ui/issues/issue-17033.rs +ui/issues/issue-17068.rs +ui/issues/issue-17121.rs +ui/issues/issue-17216.rs +ui/issues/issue-17252.rs +ui/issues/issue-17302.rs +ui/issues/issue-17322.rs +ui/issues/issue-17336.rs +ui/issues/issue-17337.rs +ui/issues/issue-17351.rs +ui/issues/issue-17361.rs +ui/issues/issue-17373.rs +ui/issues/issue-17385.rs +ui/issues/issue-17405.rs +ui/issues/issue-17441.rs +ui/issues/issue-17450.rs +ui/issues/issue-17503.rs +ui/issues/issue-17546.rs +ui/issues/issue-17551.rs +ui/issues/issue-17651.rs +ui/issues/issue-17662.rs +ui/issues/issue-17732.rs +ui/issues/issue-17734.rs +ui/issues/issue-17740.rs +ui/issues/issue-17746.rs +ui/issues/issue-17758.rs +ui/issues/issue-17771.rs +ui/issues/issue-17800.rs +ui/issues/issue-17816.rs +ui/issues/issue-17877.rs +ui/issues/issue-17897.rs +ui/issues/issue-17904-2.rs +ui/issues/issue-17904.rs +ui/issues/issue-17905-2.rs +ui/issues/issue-17905.rs +ui/issues/issue-17933.rs +ui/issues/issue-17954.rs +ui/issues/issue-17959.rs +ui/issues/issue-17994.rs +ui/issues/issue-17999.rs +ui/issues/issue-18058.rs +ui/issues/issue-18088.rs +ui/issues/issue-18107.rs +ui/issues/issue-18110.rs +ui/issues/issue-18119.rs +ui/issues/issue-18159.rs +ui/issues/issue-18173.rs +ui/issues/issue-18183.rs +ui/issues/issue-18188.rs +ui/issues/issue-18232.rs +ui/issues/issue-18352.rs +ui/issues/issue-18353.rs +ui/issues/issue-18389.rs +ui/issues/issue-18423.rs +ui/issues/issue-18446-2.rs +ui/issues/issue-18446.rs +ui/issues/issue-18464.rs +ui/issues/issue-18501.rs +ui/issues/issue-18514.rs +ui/issues/issue-18532.rs +ui/issues/issue-18539.rs +ui/issues/issue-18566.rs +ui/issues/issue-18611.rs +ui/issues/issue-18685.rs +ui/issues/issue-18711.rs +ui/issues/issue-18767.rs +ui/issues/issue-18783.rs +ui/issues/issue-18809.rs +ui/issues/issue-18845.rs +ui/issues/issue-18859.rs +ui/issues/issue-18906.rs +ui/issues/issue-18913.rs +ui/issues/issue-18919.rs +ui/issues/issue-18952.rs +ui/issues/issue-18959.rs +ui/issues/issue-18988.rs +ui/issues/issue-19001.rs +ui/issues/issue-19037.rs +ui/issues/issue-19086.rs +ui/issues/issue-19097.rs +ui/issues/issue-19098.rs +ui/issues/issue-19100.rs +ui/issues/issue-19127.rs +ui/issues/issue-19129-1.rs +ui/issues/issue-19129-2.rs +ui/issues/issue-19135.rs +ui/issues/issue-19244-1.rs +ui/issues/issue-19244-2.rs +ui/issues/issue-19293.rs +ui/issues/issue-19340-1.rs +ui/issues/issue-19340-2.rs +ui/issues/issue-19367.rs +ui/issues/issue-19380.rs +ui/issues/issue-19398.rs +ui/issues/issue-19404.rs +ui/issues/issue-19479.rs +ui/issues/issue-19482.rs +ui/issues/issue-19499.rs +ui/issues/issue-19601.rs +ui/issues/issue-19631.rs +ui/issues/issue-19632.rs +ui/issues/issue-19692.rs +ui/issues/issue-19734.rs +ui/issues/issue-19811-escape-unicode.rs +ui/issues/issue-19850.rs +ui/issues/issue-19922.rs +ui/issues/issue-19982.rs +ui/issues/issue-19991.rs +ui/issues/issue-20009.rs +ui/issues/issue-20055-box-trait.rs +ui/issues/issue-20055-box-unsized-array.rs +ui/issues/issue-20162.rs +ui/issues/issue-20174.rs +ui/issues/issue-20186.rs +ui/issues/issue-20225.rs +ui/issues/issue-20261.rs +ui/issues/issue-20313-rpass.rs +ui/issues/issue-20313.rs +ui/issues/issue-20389.rs +ui/issues/issue-20396.rs +ui/issues/issue-20413.rs +ui/issues/issue-20414.rs +ui/issues/issue-20427.rs +ui/issues/issue-20433.rs +ui/issues/issue-20454.rs +ui/issues/issue-20544.rs +ui/issues/issue-20575.rs +ui/issues/issue-20644.rs +ui/issues/issue-20676.rs +ui/issues/issue-20714.rs +ui/issues/issue-2074.rs +ui/issues/issue-20763-1.rs +ui/issues/issue-20763-2.rs +ui/issues/issue-20772.rs +ui/issues/issue-20797.rs +ui/issues/issue-20803.rs +ui/issues/issue-20831-debruijn.rs +ui/issues/issue-20847.rs +ui/issues/issue-20939.rs +ui/issues/issue-20953.rs +ui/issues/issue-20971.rs +ui/issues/issue-21033.rs +ui/issues/issue-21140.rs +ui/issues/issue-21160.rs +ui/issues/issue-21174-2.rs +ui/issues/issue-21174.rs +ui/issues/issue-21177.rs +ui/issues/issue-21202.rs +ui/issues/issue-21245.rs +ui/issues/issue-21291.rs +ui/issues/issue-21306.rs +ui/issues/issue-21332.rs +ui/issues/issue-21361.rs +ui/issues/issue-21384.rs +ui/issues/issue-21400.rs +ui/issues/issue-21402.rs +ui/issues/issue-21449.rs +ui/issues/issue-2150.rs +ui/issues/issue-2151.rs +ui/issues/issue-21546.rs +ui/issues/issue-21554.rs +ui/issues/issue-21596.rs +ui/issues/issue-21600.rs +ui/issues/issue-21622.rs +ui/issues/issue-21634.rs +ui/issues/issue-21655.rs +ui/issues/issue-2170-exe.rs +ui/issues/issue-21701.rs +ui/issues/issue-21763.rs +ui/issues/issue-21891.rs +ui/issues/issue-2190-1.rs +ui/issues/issue-21909.rs +ui/issues/issue-21922.rs +ui/issues/issue-21946.rs +ui/issues/issue-21950.rs +ui/issues/issue-21974.rs +ui/issues/issue-22008.rs +ui/issues/issue-22034.rs +ui/issues/issue-22036.rs +ui/issues/issue-2214.rs +ui/issues/issue-22258.rs +ui/issues/issue-22289.rs +ui/issues/issue-22312.rs +ui/issues/issue-22346.rs +ui/issues/issue-22356.rs +ui/issues/issue-22370.rs +ui/issues/issue-22403.rs +ui/issues/issue-22426.rs +ui/issues/issue-22434.rs +ui/issues/issue-22468.rs +ui/issues/issue-22471.rs +ui/issues/issue-22577.rs +ui/issues/issue-22599.rs +ui/issues/issue-22603.rs +ui/issues/issue-22629.rs +ui/issues/issue-22638.rs +ui/issues/issue-22644.rs +ui/issues/issue-22673.rs +ui/issues/issue-22684.rs +ui/issues/issue-22706.rs +ui/issues/issue-22777.rs +ui/issues/issue-22781.rs +ui/issues/issue-22789.rs +ui/issues/issue-2281-part1.rs +ui/issues/issue-22814.rs +ui/issues/issue-2284.rs +ui/issues/issue-22864-1.rs +ui/issues/issue-22864-2.rs +ui/issues/issue-22872.rs +ui/issues/issue-22874.rs +ui/issues/issue-2288.rs +ui/issues/issue-22886.rs +ui/issues/issue-22894.rs +ui/issues/issue-22933-1.rs +ui/issues/issue-22933-2.rs +ui/issues/issue-22992-2.rs +ui/issues/issue-22992.rs +ui/issues/issue-23024.rs +ui/issues/issue-23036.rs +ui/issues/issue-23041.rs +ui/issues/issue-23046.rs +ui/issues/issue-23073.rs +ui/issues/issue-2311-2.rs +ui/issues/issue-2311.rs +ui/issues/issue-2312.rs +ui/issues/issue-23122-1.rs +ui/issues/issue-23122-2.rs +ui/issues/issue-2316-c.rs +ui/issues/issue-23173.rs +ui/issues/issue-23189.rs +ui/issues/issue-23217.rs +ui/issues/issue-23253.rs +ui/issues/issue-23261.rs +ui/issues/issue-23281.rs +ui/issues/issue-23304-1.rs +ui/issues/issue-23304-2.rs +ui/issues/issue-23311.rs +ui/issues/issue-23336.rs +ui/issues/issue-23354-2.rs +ui/issues/issue-23354.rs +ui/issues/issue-23406.rs +ui/issues/issue-23433.rs +ui/issues/issue-23442.rs +ui/issues/issue-23477.rs +ui/issues/issue-23485.rs +ui/issues/issue-23491.rs +ui/issues/issue-23543.rs +ui/issues/issue-23544.rs +ui/issues/issue-23550.rs +ui/issues/issue-23589.rs +ui/issues/issue-23699.rs +ui/issues/issue-2380-b.rs +ui/issues/issue-23808.rs +ui/issues/issue-2383.rs +ui/issues/issue-23891.rs +ui/issues/issue-23898.rs +ui/issues/issue-23958.rs +ui/issues/issue-23966.rs +ui/issues/issue-23992.rs +ui/issues/issue-24013.rs +ui/issues/issue-24036.rs +ui/issues/issue-24086.rs +ui/issues/issue-2414-c.rs +ui/issues/issue-24161.rs +ui/issues/issue-24227.rs +ui/issues/issue-2428.rs +ui/issues/issue-24308.rs +ui/issues/issue-24322.rs +ui/issues/issue-24352.rs +ui/issues/issue-24353.rs +ui/issues/issue-24357.rs +ui/issues/issue-24363.rs +ui/issues/issue-24365.rs +ui/issues/issue-24389.rs +ui/issues/issue-24424.rs +ui/issues/issue-24434.rs +ui/issues/issue-2445-b.rs +ui/issues/issue-2445.rs +ui/issues/issue-24533.rs +ui/issues/issue-24589.rs +ui/issues/issue-2463.rs +ui/issues/issue-24682.rs +ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-lib.rs +ui/issues/issue-24687-embed-debuginfo/auxiliary/issue-24687-mbcs-in-comments.rs +ui/issues/issue-2470-bounds-check-overflow.rs +ui/issues/issue-2472.rs +ui/issues/issue-24779.rs +ui/issues/issue-24819.rs +ui/issues/issue-2487-a.rs +ui/issues/issue-24945-repeat-dash-opts.rs +ui/issues/issue-24947.rs +ui/issues/issue-24954.rs +ui/issues/issue-2502.rs +ui/issues/issue-25076.rs +ui/issues/issue-25089.rs +ui/issues/issue-25145.rs +ui/issues/issue-25180.rs +ui/issues/issue-25185.rs +ui/issues/issue-2526-a.rs +ui/issues/issue-25279.rs +ui/issues/issue-25343.rs +ui/issues/issue-25368.rs +ui/issues/issue-25386.rs +ui/issues/issue-25394.rs +ui/issues/issue-25467.rs +ui/issues/issue-25497.rs +ui/issues/issue-2550.rs +ui/issues/issue-25515.rs +ui/issues/issue-25549-multiple-drop.rs +ui/issues/issue-25579.rs +ui/issues/issue-25679.rs +ui/issues/issue-25693.rs +ui/issues/issue-25746-bool-transmute.rs +ui/issues/issue-25757.rs +ui/issues/issue-25810.rs +ui/issues/issue-2590.rs +ui/issues/issue-25901.rs +ui/issues/issue-26056.rs +ui/issues/issue-26093.rs +ui/issues/issue-26095.rs +ui/issues/issue-26127.rs +ui/issues/issue-26186.rs +ui/issues/issue-26205.rs +ui/issues/issue-26217.rs +ui/issues/issue-26237.rs +ui/issues/issue-2631-b.rs +ui/issues/issue-2642.rs +ui/issues/issue-26468.rs +ui/issues/issue-26472.rs +ui/issues/issue-26484.rs +ui/issues/issue-26614.rs +ui/issues/issue-26619.rs +ui/issues/issue-26641.rs +ui/issues/issue-26646.rs +ui/issues/issue-26655.rs +ui/issues/issue-26709.rs +ui/issues/issue-26802.rs +ui/issues/issue-26805.rs +ui/issues/issue-26812.rs +ui/issues/issue-26948.rs +ui/issues/issue-26997.rs +ui/issues/issue-27008.rs +ui/issues/issue-27033.rs +ui/issues/issue-27042.rs +ui/issues/issue-27054-primitive-binary-ops.rs +ui/issues/issue-27078.rs +ui/issues/issue-2708.rs +ui/issues/issue-27105.rs +ui/issues/issue-2723-b.rs +ui/issues/issue-27240.rs +ui/issues/issue-27268.rs +ui/issues/issue-27281.rs +ui/issues/issue-27340.rs +ui/issues/issue-27401-dropflag-reinit.rs +ui/issues/issue-27433.rs +ui/issues/issue-27592.rs +ui/issues/issue-2761.rs +ui/issues/issue-27639.rs +ui/issues/issue-27697.rs +ui/issues/issue-27815.rs +ui/issues/issue-27842.rs +ui/issues/issue-27889.rs +ui/issues/issue-27942.rs +ui/issues/issue-27949.rs +ui/issues/issue-27997.rs +ui/issues/issue-28105.rs +ui/issues/issue-28109.rs +ui/issues/issue-28181.rs +ui/issues/issue-2823.rs +ui/issues/issue-28279.rs +ui/issues/issue-28344.rs +ui/issues/issue-28433.rs +ui/issues/issue-28472.rs +ui/issues/issue-2848.rs +ui/issues/issue-2849.rs +ui/issues/issue-28498-must-work-ex1.rs +ui/issues/issue-28498-must-work-ex2.rs +ui/issues/issue-28498-ugeh-ex1.rs +ui/issues/issue-28550.rs +ui/issues/issue-28561.rs +ui/issues/issue-28568.rs +ui/issues/issue-28586.rs +ui/issues/issue-28600.rs +ui/issues/issue-28625.rs +ui/issues/issue-28776.rs +ui/issues/issue-28777.rs +ui/issues/issue-28828.rs +ui/issues/issue-28839.rs +ui/issues/issue-28936.rs +ui/issues/issue-2895.rs +ui/issues/issue-28971.rs +ui/issues/issue-28983.rs +ui/issues/issue-28999.rs +ui/issues/issue-29030.rs +ui/issues/issue-29037.rs +ui/issues/issue-2904.rs +ui/issues/issue-29048.rs +ui/issues/issue-29053.rs +ui/issues/issue-29071-2.rs +ui/issues/issue-29071.rs +ui/issues/issue-29092.rs +ui/issues/issue-29147-rpass.rs +ui/issues/issue-29147.rs +ui/issues/issue-29265.rs +ui/issues/issue-29276.rs +ui/issues/issue-2935.rs +ui/issues/issue-29466.rs +ui/issues/issue-29485.rs +ui/issues/issue-2951.rs +ui/issues/issue-29516.rs +ui/issues/issue-29522.rs +ui/issues/issue-29540.rs +ui/issues/issue-29663.rs +ui/issues/issue-29668.rs +ui/issues/issue-29710.rs +ui/issues/issue-29723.rs +ui/issues/issue-29740.rs +ui/issues/issue-29743.rs +ui/issues/issue-29821.rs +ui/issues/issue-29857.rs +ui/issues/issue-29861.rs +ui/issues/issue-2989.rs +ui/issues/issue-29948.rs +ui/issues/issue-2995.rs +ui/issues/issue-30018-panic.rs +ui/issues/issue-30081.rs +ui/issues/issue-3012-2.rs +ui/issues/issue-30123.rs +ui/issues/issue-3021-b.rs +ui/issues/issue-3021-d.rs +ui/issues/issue-30236.rs +ui/issues/issue-30255.rs +ui/issues/issue-3026.rs +ui/issues/issue-3029.rs +ui/issues/issue-3037.rs +ui/issues/issue-30371.rs +ui/issues/issue-3038.rs +ui/issues/issue-30380.rs +ui/issues/issue-3052.rs +ui/issues/issue-30530.rs +ui/issues/issue-30589.rs +ui/issues/issue-30615.rs +ui/issues/issue-30756.rs +ui/issues/issue-30891.rs +ui/issues/issue-3091.rs +ui/issues/issue-31011.rs +ui/issues/issue-3109.rs +ui/issues/issue-3121.rs +ui/issues/issue-31260.rs +ui/issues/issue-31267-additional.rs +ui/issues/issue-31267.rs +ui/issues/issue-31299.rs +ui/issues/issue-3136-b.rs +ui/issues/issue-3149.rs +ui/issues/issue-31511.rs +ui/issues/issue-3154.rs +ui/issues/issue-31702.rs +ui/issues/issue-31769.rs +ui/issues/issue-31776.rs +ui/issues/issue-31910.rs +ui/issues/issue-32004.rs +ui/issues/issue-32008.rs +ui/issues/issue-32086.rs +ui/issues/issue-32122-deref-coercions-composition/issue-32122-1.rs +ui/issues/issue-32122-deref-coercions-composition/issue-32122-2.rs +ui/issues/issue-3214.rs +ui/issues/issue-3220.rs +ui/issues/issue-32292.rs +ui/issues/issue-32324.rs +ui/issues/issue-32326.rs +ui/issues/issue-32377.rs +ui/issues/issue-32389.rs +ui/issues/issue-32518.rs +ui/issues/issue-32655.rs +ui/issues/issue-32782.rs +ui/issues/issue-32797.rs +ui/issues/issue-32805.rs +ui/issues/issue-3290.rs +ui/issues/issue-32950.rs +ui/issues/issue-32995-2.rs +ui/issues/issue-32995.rs +ui/issues/issue-33202.rs +ui/issues/issue-33241.rs +ui/issues/issue-33287.rs +ui/issues/issue-33293.rs +ui/issues/issue-33387.rs +ui/issues/issue-3344.rs +ui/issues/issue-33461.rs +ui/issues/issue-33504.rs +ui/issues/issue-33525.rs +ui/issues/issue-33571.rs +ui/issues/issue-33687.rs +ui/issues/issue-33770.rs +ui/issues/issue-3389.rs +ui/issues/issue-33941.rs +ui/issues/issue-33992.rs +ui/issues/issue-34047.rs +ui/issues/issue-34074.rs +ui/issues/issue-34209.rs +ui/issues/issue-34229.rs +ui/issues/issue-3424.rs +ui/issues/issue-3429.rs +ui/issues/issue-34334.rs +ui/issues/issue-34349.rs +ui/issues/issue-34373.rs +ui/issues/issue-34418.rs +ui/issues/issue-34427.rs +ui/issues/issue-3447.rs +ui/issues/issue-34503.rs +ui/issues/issue-34569.rs +ui/issues/issue-34571.rs +ui/issues/issue-34751.rs +ui/issues/issue-3477.rs +ui/issues/issue-34780.rs +ui/issues/issue-34796.rs +ui/issues/issue-34839.rs +ui/issues/issue-3500.rs +ui/issues/issue-35139.rs +ui/issues/issue-3521-2.rs +ui/issues/issue-35241.rs +ui/issues/issue-35423.rs +ui/issues/issue-3556.rs +ui/issues/issue-35570.rs +ui/issues/issue-3559.rs +ui/issues/issue-35600.rs +ui/issues/issue-3574.rs +ui/issues/issue-35815.rs +ui/issues/issue-35976.rs +ui/issues/issue-35988.rs +ui/issues/issue-36023.rs +ui/issues/issue-36036-associated-type-layout.rs +ui/issues/issue-36075.rs +ui/issues/issue-3609.rs +ui/issues/issue-36116.rs +ui/issues/issue-36260.rs +ui/issues/issue-36278-prefix-nesting.rs +ui/issues/issue-36299.rs +ui/issues/issue-36379.rs +ui/issues/issue-36400.rs +ui/issues/issue-36474.rs +ui/issues/issue-3656.rs +ui/issues/issue-3668-non-constant-value-in-constant/issue-3668-2.rs +ui/issues/issue-3668-non-constant-value-in-constant/issue-3668.rs +ui/issues/issue-36744-bitcast-args-if-needed.rs +ui/issues/issue-36786-resolve-call.rs +ui/issues/issue-3680.rs +ui/issues/issue-36816.rs +ui/issues/issue-36836.rs +ui/issues/issue-36839.rs +ui/issues/issue-36856.rs +ui/issues/issue-36936.rs +ui/issues/issue-36954.rs +ui/issues/issue-3702-2.rs +ui/issues/issue-3702.rs +ui/issues/issue-37051.rs +ui/issues/issue-37109.rs +ui/issues/issue-37131.rs +ui/issues/issue-37311-type-length-limit/issue-37311.rs +ui/issues/issue-37510.rs +ui/issues/issue-3753.rs +ui/issues/issue-37534.rs +ui/issues/issue-37576.rs +ui/issues/issue-3763.rs +ui/issues/issue-37665.rs +ui/issues/issue-37686.rs +ui/issues/issue-37725.rs +ui/issues/issue-37733.rs +ui/issues/issue-3779.rs +ui/issues/issue-37884.rs +ui/issues/issue-38160.rs +ui/issues/issue-38190.rs +ui/issues/issue-38226.rs +ui/issues/issue-38381.rs +ui/issues/issue-38412.rs +ui/issues/issue-38437.rs +ui/issues/issue-38458.rs +ui/issues/issue-3847.rs +ui/issues/issue-38556.rs +ui/issues/issue-38727.rs +ui/issues/issue-3874.rs +ui/issues/issue-38763.rs +ui/issues/issue-38857.rs +ui/issues/issue-38875/auxiliary/issue-38875-b.rs +ui/issues/issue-38875/issue-38875.rs +ui/issues/issue-3888-2.rs +ui/issues/issue-38919.rs +ui/issues/issue-38942.rs +ui/issues/issue-3895.rs +ui/issues/issue-38954.rs +ui/issues/issue-38987.rs +ui/issues/issue-39089.rs +ui/issues/issue-39175.rs +ui/issues/issue-39211.rs +ui/issues/issue-39367.rs +ui/issues/issue-39548.rs +ui/issues/issue-39687.rs +ui/issues/issue-39709.rs +ui/issues/issue-3979-2.rs +ui/issues/issue-3979-xcrate.rs +ui/issues/issue-3979.rs +ui/issues/issue-39808.rs +ui/issues/issue-39827.rs +ui/issues/issue-39848.rs +ui/issues/issue-3991.rs +ui/issues/issue-3993.rs +ui/issues/issue-39970.rs +ui/issues/issue-39984.rs +ui/issues/issue-40000.rs +ui/issues/issue-40136.rs +ui/issues/issue-40235.rs +ui/issues/issue-4025.rs +ui/issues/issue-40288-2.rs +ui/issues/issue-40288.rs +ui/issues/issue-40350.rs +ui/issues/issue-40402-ref-hints/issue-40402-1.rs +ui/issues/issue-40402-ref-hints/issue-40402-2.rs +ui/issues/issue-40408.rs +ui/issues/issue-40610.rs +ui/issues/issue-40749.rs +ui/issues/issue-40782.rs +ui/issues/issue-40827.rs +ui/issues/issue-40845.rs +ui/issues/issue-40861.rs +ui/issues/issue-40883.rs +ui/issues/issue-40951.rs +ui/issues/issue-41053.rs +ui/issues/issue-41139.rs +ui/issues/issue-41213.rs +ui/issues/issue-41229-ref-str.rs +ui/issues/issue-41272.rs +ui/issues/issue-41298.rs +ui/issues/issue-41479.rs +ui/issues/issue-41498.rs +ui/issues/issue-41549.rs +ui/issues/issue-41604.rs +ui/issues/issue-41628.rs +ui/issues/issue-41652/auxiliary/issue-41652-b.rs +ui/issues/issue-41652/issue-41652.rs +ui/issues/issue-41677.rs +ui/issues/issue-41696.rs +ui/issues/issue-41726.rs +ui/issues/issue-41742.rs +ui/issues/issue-41744.rs +ui/issues/issue-41849-variance-req.rs +ui/issues/issue-41880.rs +ui/issues/issue-41888.rs +ui/issues/issue-41936-variance-coerce-unsized-cycle.rs +ui/issues/issue-41974.rs +ui/issues/issue-41998.rs +ui/issues/issue-42007.rs +ui/issues/issue-4208.rs +ui/issues/issue-42106.rs +ui/issues/issue-42148.rs +ui/issues/issue-42210.rs +ui/issues/issue-4228.rs +ui/issues/issue-42312.rs +ui/issues/issue-42453.rs +ui/issues/issue-42467.rs +ui/issues/issue-4252.rs +ui/issues/issue-42552.rs +ui/issues/issue-4265.rs +ui/issues/issue-42755.rs +ui/issues/issue-42796.rs +ui/issues/issue-42880.rs +ui/issues/issue-42956.rs +ui/issues/issue-43057.rs +ui/issues/issue-43205.rs +ui/issues/issue-43250.rs +ui/issues/issue-43291.rs +ui/issues/issue-4333.rs +ui/issues/issue-4335.rs +ui/issues/issue-43355.rs +ui/issues/issue-43357.rs +ui/issues/issue-43420-no-over-suggest.rs +ui/issues/issue-43424.rs +ui/issues/issue-43431.rs +ui/issues/issue-43483.rs +ui/issues/issue-43692.rs +ui/issues/issue-43806.rs +ui/issues/issue-43853.rs +ui/issues/issue-4387.rs +ui/issues/issue-43910.rs +ui/issues/issue-43923.rs +ui/issues/issue-43925.rs +ui/issues/issue-43926.rs +ui/issues/issue-43988.rs +ui/issues/issue-44023.rs +ui/issues/issue-44056.rs +ui/issues/issue-44078.rs +ui/issues/issue-44216-add-instant.rs +ui/issues/issue-44216-add-system-time.rs +ui/issues/issue-44216-sub-instant.rs +ui/issues/issue-44216-sub-system-time.rs +ui/issues/issue-44239.rs +ui/issues/issue-44247.rs +ui/issues/issue-44405.rs +ui/issues/issue-4464.rs +ui/issues/issue-44730.rs +ui/issues/issue-44851.rs +ui/issues/issue-4517.rs +ui/issues/issue-4541.rs +ui/issues/issue-4542.rs +ui/issues/issue-45425.rs +ui/issues/issue-4545.rs +ui/issues/issue-45510.rs +ui/issues/issue-45562.rs +ui/issues/issue-45697-1.rs +ui/issues/issue-45697.rs +ui/issues/issue-45730.rs +ui/issues/issue-45731.rs +ui/issues/issue-45801.rs +ui/issues/issue-45965.rs +ui/issues/issue-46069.rs +ui/issues/issue-46101.rs +ui/issues/issue-46302.rs +ui/issues/issue-46311.rs +ui/issues/issue-46332.rs +ui/issues/issue-46471-1.rs +ui/issues/issue-46472.rs +ui/issues/issue-46604.rs +ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.rs +ui/issues/issue-46771.rs +ui/issues/issue-46855.rs +ui/issues/issue-46964.rs +ui/issues/issue-46983.rs +ui/issues/issue-47073-zero-padded-tuple-struct-indices.rs +ui/issues/issue-47094.rs +ui/issues/issue-47184.rs +ui/issues/issue-47309.rs +ui/issues/issue-4734.rs +ui/issues/issue-4735.rs +ui/issues/issue-4736.rs +ui/issues/issue-47364.rs +ui/issues/issue-47377.rs +ui/issues/issue-47380.rs +ui/issues/issue-47486.rs +ui/issues/issue-4759-1.rs +ui/issues/issue-4759.rs +ui/issues/issue-47638.rs +ui/issues/issue-47673.rs +ui/issues/issue-47703-1.rs +ui/issues/issue-47703-tuple.rs +ui/issues/issue-47703.rs +ui/issues/issue-47715.rs +ui/issues/issue-47722.rs +ui/issues/issue-48006.rs +ui/issues/issue-48131.rs +ui/issues/issue-48132.rs +ui/issues/issue-48159.rs +ui/issues/issue-48276.rs +ui/issues/issue-4830.rs +ui/issues/issue-48364.rs +ui/issues/issue-48728.rs +ui/issues/issue-4875.rs +ui/issues/issue-48838.rs +ui/issues/issue-48984.rs +ui/issues/issue-49298.rs +ui/issues/issue-4935.rs +ui/issues/issue-49544.rs +ui/issues/issue-49632.rs +ui/issues/issue-4968.rs +ui/issues/issue-4972.rs +ui/issues/issue-49824.rs +ui/issues/issue-49854.rs +ui/issues/issue-49919.rs +ui/issues/issue-49934-errors.rs +ui/issues/issue-49934.rs +ui/issues/issue-49955.rs +ui/issues/issue-49973.rs +ui/issues/issue-50187.rs +ui/issues/issue-50403.rs +ui/issues/issue-50411.rs +ui/issues/issue-50415.rs +ui/issues/issue-50442.rs +ui/issues/issue-50471.rs +ui/issues/issue-50518.rs +ui/issues/issue-50571.rs +ui/issues/issue-50581.rs +ui/issues/issue-50582.rs +ui/issues/issue-50585.rs +ui/issues/issue-50600.rs +ui/issues/issue-50618.rs +ui/issues/issue-5062.rs +ui/issues/issue-5067.rs +ui/issues/issue-50688.rs +ui/issues/issue-50714-1.rs +ui/issues/issue-50714.rs +ui/issues/issue-50761.rs +ui/issues/issue-50781.rs +ui/issues/issue-50802.rs +ui/issues/issue-50811.rs +ui/issues/issue-5100.rs +ui/issues/issue-51022.rs +ui/issues/issue-51044.rs +ui/issues/issue-51102.rs +ui/issues/issue-51116.rs +ui/issues/issue-51154.rs +ui/issues/issue-51515.rs +ui/issues/issue-51632-try-desugar-incompatible-types.rs +ui/issues/issue-51655.rs +ui/issues/issue-51714.rs +ui/issues/issue-51798.rs +ui/issues/issue-51874.rs +ui/issues/issue-51907.rs +ui/issues/issue-5192.rs +ui/issues/issue-51947.rs +ui/issues/issue-52049.rs +ui/issues/issue-52126-assign-op-invariance.rs +ui/issues/issue-52262.rs +ui/issues/issue-5239-1.rs +ui/issues/issue-5239-2.rs +ui/issues/issue-52489.rs +ui/issues/issue-52533.rs +ui/issues/issue-52717.rs +ui/issues/issue-5280.rs +ui/issues/issue-5315.rs +ui/issues/issue-5321-immediates-with-bare-self.rs +ui/issues/issue-53251.rs +ui/issues/issue-53275.rs +ui/issues/issue-53300.rs +ui/issues/issue-53333.rs +ui/issues/issue-53348.rs +ui/issues/issue-53419.rs +ui/issues/issue-53498.rs +ui/issues/issue-53568.rs +ui/issues/issue-5358-1.rs +ui/issues/issue-53728.rs +ui/issues/issue-53843.rs +ui/issues/issue-54044.rs +ui/issues/issue-54062.rs +ui/issues/issue-54094.rs +ui/issues/issue-5439.rs +ui/issues/issue-54410.rs +ui/issues/issue-54462-mutable-noalias-correctness.rs +ui/issues/issue-54477-reduced-2.rs +ui/issues/issue-54696.rs +ui/issues/issue-5518.rs +ui/issues/issue-5521.rs +ui/issues/issue-55376.rs +ui/issues/issue-55380.rs +ui/issues/issue-5550.rs +ui/issues/issue-5554.rs +ui/issues/issue-55587.rs +ui/issues/issue-5572.rs +ui/issues/issue-55731.rs +ui/issues/issue-56128.rs +ui/issues/issue-56175.rs +ui/issues/issue-56199.rs +ui/issues/issue-56229.rs +ui/issues/issue-56237.rs +ui/issues/issue-5666.rs +ui/issues/issue-56806.rs +ui/issues/issue-56835.rs +ui/issues/issue-56870.rs +ui/issues/issue-5688.rs +ui/issues/issue-56943.rs +ui/issues/issue-5708.rs +ui/issues/issue-57156.rs +ui/issues/issue-57162.rs +ui/issues/issue-5718.rs +ui/issues/issue-57198-pass.rs +ui/issues/issue-57271.rs +ui/issues/issue-57362-1.rs +ui/issues/issue-57362-2.rs +ui/issues/issue-57399-self-return-impl-trait.rs +ui/issues/issue-5741.rs +ui/issues/issue-5754.rs +ui/issues/issue-57741-dereference-boxed-value/issue-57741-1.rs +ui/issues/issue-57741-dereference-boxed-value/issue-57741.rs +ui/issues/issue-57781.rs +ui/issues/issue-57924.rs +ui/issues/issue-58212.rs +ui/issues/issue-58375-monomorphize-default-impls.rs +ui/issues/issue-5844.rs +ui/issues/issue-58463.rs +ui/issues/issue-58712.rs +ui/issues/issue-58734.rs +ui/issues/issue-5883.rs +ui/issues/issue-5884.rs +ui/issues/issue-58857.rs +ui/issues/issue-5900.rs +ui/issues/issue-59020.rs +ui/issues/issue-5917.rs +ui/issues/issue-59326.rs +ui/issues/issue-59488.rs +ui/issues/issue-59494.rs +ui/issues/issue-5950.rs +ui/issues/issue-59756.rs +ui/issues/issue-5988.rs +ui/issues/issue-5997-outer-generic-parameter/issue-5997-enum.rs +ui/issues/issue-5997-outer-generic-parameter/issue-5997-struct.rs +ui/issues/issue-5997-outer-generic-parameter/issue-5997.rs +ui/issues/issue-60218.rs +ui/issues/issue-60622.rs +ui/issues/issue-60989.rs +ui/issues/issue-61106.rs +ui/issues/issue-61108.rs +ui/issues/issue-6117.rs +ui/issues/issue-6130.rs +ui/issues/issue-61475.rs +ui/issues/issue-6153.rs +ui/issues/issue-61623.rs +ui/issues/issue-61894.rs +ui/issues/issue-62480.rs +ui/issues/issue-6318.rs +ui/issues/issue-6344-let.rs +ui/issues/issue-6344-match.rs +ui/issues/issue-63983.rs +ui/issues/issue-64430.rs +ui/issues/issue-64559.rs +ui/issues/issue-64593.rs +ui/issues/issue-64792-bad-unicode-ctor.rs +ui/issues/issue-65131.rs +ui/issues/issue-65230.rs +ui/issues/issue-65462.rs +ui/issues/issue-6557.rs +ui/issues/issue-66308.rs +ui/issues/issue-66353.rs +ui/issues/issue-66667-function-cmp-cycle.rs +ui/issues/issue-66702-break-outside-loop-val.rs +ui/issues/issue-66706.rs +ui/issues/issue-66923-show-error-for-correct-call.rs +ui/issues/issue-67039-unsound-pin-partialeq.rs +ui/issues/issue-6738.rs +ui/issues/issue-67535.rs +ui/issues/issue-67552.rs +ui/issues/issue-68010-large-zst-consts.rs +ui/issues/issue-68696-catch-during-unwind.rs +ui/issues/issue-6892.rs +ui/issues/issue-68951.rs +ui/issues/issue-6898.rs +ui/issues/issue-69130.rs +ui/issues/issue-6919.rs +ui/issues/issue-69306.rs +ui/issues/issue-6936.rs +ui/issues/issue-69455.rs +ui/issues/issue-69602-type-err-during-codegen-ice.rs +ui/issues/issue-69683.rs +ui/issues/issue-70093/issue-70093-link-directives.rs +ui/issues/issue-70093/issue-70093.rs +ui/issues/issue-7012.rs +ui/issues/issue-70381.rs +ui/issues/issue-7044.rs +ui/issues/issue-7061.rs +ui/issues/issue-70673.rs +ui/issues/issue-70724-add_type_neq_err_label-unwrap.rs +ui/issues/issue-70746.rs +ui/issues/issue-7092.rs +ui/issues/issue-71406.rs +ui/issues/issue-71676-suggest-deref/issue-71676-1.rs +ui/issues/issue-71676-suggest-deref/issue-71676-2.rs +ui/issues/issue-7178.rs +ui/issues/issue-72002.rs +ui/issues/issue-72076.rs +ui/issues/issue-72278.rs +ui/issues/issue-7246.rs +ui/issues/issue-7268.rs +ui/issues/issue-72839-error-overflow.rs +ui/issues/issue-72933-match-stack-overflow.rs +ui/issues/issue-73112.rs +ui/issues/issue-73229.rs +ui/issues/issue-7344.rs +ui/issues/issue-7364.rs +ui/issues/issue-74082.rs +ui/issues/issue-74564-if-expr-stack-overflow.rs +ui/issues/issue-7519-match-unit-in-arg.rs +ui/issues/issue-75283.rs +ui/issues/issue-7563.rs +ui/issues/issue-75704.rs +ui/issues/issue-7575.rs +ui/issues/issue-76042.rs +ui/issues/issue-7607-1.rs +ui/issues/issue-7607-2.rs +ui/issues/issue-76077-inaccesible-private-fields/issue-76077-1.rs +ui/issues/issue-76077-inaccesible-private-fields/issue-76077.rs +ui/issues/issue-76191.rs +ui/issues/issue-7660.rs +ui/issues/issue-7663.rs +ui/issues/issue-7673-cast-generically-implemented-trait.rs +ui/issues/issue-77218/issue-77218-2.rs +ui/issues/issue-77218/issue-77218.rs +ui/issues/issue-7784.rs +ui/issues/issue-77919.rs +ui/issues/issue-78192.rs +ui/issues/issue-78622.rs +ui/issues/issue-7867.rs +ui/issues/issue-78957.rs +ui/issues/issue-7899.rs +ui/issues/issue-7911.rs +ui/issues/issue-7970a.rs +ui/issues/issue-8044.rs +ui/issues/issue-80607.rs +ui/issues/issue-81584.rs +ui/issues/issue-8171-default-method-self-inherit-builtin-trait.rs +ui/issues/issue-81918.rs +ui/issues/issue-8248.rs +ui/issues/issue-8249.rs +ui/issues/issue-8259.rs +ui/issues/issue-83048.rs +ui/issues/issue-8391.rs +ui/issues/issue-8398.rs +ui/issues/issue-8401.rs +ui/issues/issue-8498.rs +ui/issues/issue-8506.rs +ui/issues/issue-8521.rs +ui/issues/issue-85461.rs +ui/issues/issue-8578.rs +ui/issues/issue-86756.rs +ui/issues/issue-87199.rs +ui/issues/issue-8727.rs +ui/issues/issue-87490.rs +ui/issues/issue-8761.rs +ui/issues/issue-8767.rs +ui/issues/issue-87707.rs +ui/issues/issue-8783.rs +ui/issues/issue-88150.rs +ui/issues/issue-8860.rs +ui/issues/issue-8898.rs +ui/issues/issue-9047.rs +ui/issues/issue-9110.rs +ui/issues/issue-9123.rs +ui/issues/issue-9129.rs +ui/issues/issue-91489.rs +ui/issues/issue-9155.rs +ui/issues/issue-9188.rs +ui/issues/issue-9243.rs +ui/issues/issue-9249.rs +ui/issues/issue-9259.rs +ui/issues/issue-92741.rs +ui/issues/issue-9382.rs +ui/issues/issue-9446.rs +ui/issues/issue-9575.rs +ui/issues/issue-9719.rs +ui/issues/issue-9725.rs +ui/issues/issue-9737.rs +ui/issues/issue-9814.rs +ui/issues/issue-98299.rs +ui/issues/issue-9837.rs +ui/issues/issue-9906.rs +ui/issues/issue-9918.rs +ui/issues/issue-9942.rs +ui/issues/issue-9951.rs +ui/issues/issue-9968.rs +ui/issues/issue-99838.rs +ui/iterators/issue-28098.rs +ui/iterators/issue-58952-filter-type-length.rs +ui/lang-items/issue-19660.rs +ui/lang-items/issue-83471.rs +ui/lang-items/issue-87573.rs +ui/late-bound-lifetimes/issue-36381.rs +ui/late-bound-lifetimes/issue-47511.rs +ui/late-bound-lifetimes/issue-80618.rs +ui/layout/issue-112048-unsizing-field-order.rs +ui/layout/issue-112048-unsizing-niche.rs +ui/layout/issue-113941.rs +ui/layout/issue-60431-unsized-tail-behind-projection.rs +ui/layout/issue-84108.rs +ui/layout/issue-96158-scalarpair-payload-might-be-uninit.rs +ui/layout/issue-96185-overaligned-enum.rs +ui/let-else/issue-100103.rs +ui/let-else/issue-102317.rs +ui/let-else/issue-94176.rs +ui/let-else/issue-99975.rs +ui/lifetimes/auxiliary/issue-91763-aux.rs +ui/lifetimes/issue-103582-hint-for-missing-lifetime-bound-on-trait-object-using-type-alias.rs +ui/lifetimes/issue-104432-unused-lifetimes-in-expansion.rs +ui/lifetimes/issue-105227.rs +ui/lifetimes/issue-105507.rs +ui/lifetimes/issue-105675.rs +ui/lifetimes/issue-107492-default-value-for-lifetime.rs +ui/lifetimes/issue-107988.rs +ui/lifetimes/issue-17728.rs +ui/lifetimes/issue-19707.rs +ui/lifetimes/issue-26638.rs +ui/lifetimes/issue-34979.rs +ui/lifetimes/issue-36744-without-calls.rs +ui/lifetimes/issue-54378.rs +ui/lifetimes/issue-55796.rs +ui/lifetimes/issue-64173-unused-lifetimes.rs +ui/lifetimes/issue-67498.rs +ui/lifetimes/issue-69314.rs +ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs +ui/lifetimes/issue-76168-hr-outlives-2.rs +ui/lifetimes/issue-76168-hr-outlives-3.rs +ui/lifetimes/issue-76168-hr-outlives.rs +ui/lifetimes/issue-77175.rs +ui/lifetimes/issue-79187-2.rs +ui/lifetimes/issue-79187.rs +ui/lifetimes/issue-83737-binders-across-types.rs +ui/lifetimes/issue-83737-erasing-bound-vars.rs +ui/lifetimes/issue-83753-invalid-associated-type-supertrait-hrtb.rs +ui/lifetimes/issue-83907-invalid-fn-like-path.rs +ui/lifetimes/issue-84398.rs +ui/lifetimes/issue-84604.rs +ui/lifetimes/issue-90170-elision-mismatch.rs +ui/lifetimes/issue-90600-expected-return-static-indirect.rs +ui/lifetimes/issue-91763.rs +ui/lifetimes/issue-93911.rs +ui/lifetimes/issue-95023.rs +ui/lifetimes/issue-97193.rs +ui/lifetimes/issue-97194.rs +ui/lifetimes/lifetime-errors/issue_74400.rs +ui/limits/issue-15919-32.rs +ui/limits/issue-15919-64.rs +ui/limits/issue-17913.rs +ui/limits/issue-55878.rs +ui/limits/issue-56762.rs +ui/limits/issue-69485-var-size-diffs-too-large.rs +ui/limits/issue-75158-64.rs +ui/linkage-attr/auxiliary/issue-12133-dylib.rs +ui/linkage-attr/auxiliary/issue-12133-dylib2.rs +ui/linkage-attr/auxiliary/issue-12133-rlib.rs +ui/linkage-attr/issue-10755.rs +ui/linkage-attr/issue-109144.rs +ui/linkage-attr/issue-12133-1.rs +ui/linkage-attr/issue-12133-2.rs +ui/linkage-attr/issue-12133-3.rs +ui/lint/dead-code/issue-41883.rs +ui/lint/dead-code/issue-59003.rs +ui/lint/dead-code/issue-68408-false-positive.rs +ui/lint/dead-code/issue-85071-2.rs +ui/lint/dead-code/issue-85071.rs +ui/lint/dead-code/issue-85255.rs +ui/lint/issue-101284.rs +ui/lint/issue-102705.rs +ui/lint/issue-103317.rs +ui/lint/issue-103435-extra-parentheses.rs +ui/lint/issue-104392.rs +ui/lint/issue-104897.rs +ui/lint/issue-106991.rs +ui/lint/issue-108155.rs +ui/lint/issue-109152.rs +ui/lint/issue-109529.rs +ui/lint/issue-110573.rs +ui/lint/issue-111359.rs +ui/lint/issue-112489.rs +ui/lint/issue-117949.rs +ui/lint/issue-121070-let-range.rs +ui/lint/issue-14309.rs +ui/lint/issue-14837.rs +ui/lint/issue-17718-const-naming.rs +ui/lint/issue-1866.rs +ui/lint/issue-19102.rs +ui/lint/issue-20343.rs +ui/lint/issue-30302.rs +ui/lint/issue-31924-non-snake-ffi.rs +ui/lint/issue-34798.rs +ui/lint/issue-35075.rs +ui/lint/issue-47775-nested-macro-unnecessary-parens-arg.rs +ui/lint/issue-49588-non-shorthand-field-patterns-in-pattern-macro.rs +ui/lint/issue-54099-camel-case-underscore-types.rs +ui/lint/issue-57410-1.rs +ui/lint/issue-57410.rs +ui/lint/issue-63364.rs +ui/lint/issue-66362-no-snake-case-warning-for-field-puns.rs +ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs +ui/lint/issue-79546-fuel-ice.rs +ui/lint/issue-79744.rs +ui/lint/issue-80988.rs +ui/lint/issue-81218.rs +ui/lint/issue-83477.rs +ui/lint/issue-87274-paren-parent.rs +ui/lint/issue-89469.rs +ui/lint/issue-90614-accept-allow-text-direction-codepoint-in-comment-lint.rs +ui/lint/issue-97094.rs +ui/lint/issue-99387.rs +ui/lint/let_underscore/issue-119696-err-on-fn.rs +ui/lint/let_underscore/issue-119697-extra-let.rs +ui/lint/must_not_suspend/issue-89562.rs +ui/lint/unused/issue-103320-must-use-ops.rs +ui/lint/unused/issue-104397.rs +ui/lint/unused/issue-105061-array-lint.rs +ui/lint/unused/issue-105061-should-lint.rs +ui/lint/unused/issue-105061.rs +ui/lint/unused/issue-117142-invalid-remove-parens.rs +ui/lint/unused/issue-117284-arg-in-macro.rs +ui/lint/unused/issue-119383-if-let-guard.rs +ui/lint/unused/issue-30730.rs +ui/lint/unused/issue-46576.rs +ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs +ui/lint/unused/issue-54180-unused-ref-field.rs +ui/lint/unused/issue-54538-unused-parens-lint.rs +ui/lint/unused/issue-59896.rs +ui/lint/unused/issue-67691-unused-field-in-or-pattern.rs +ui/lint/unused/issue-70041.rs +ui/lint/unused/issue-71290-unused-paren-binop.rs +ui/lint/unused/issue-74883-unused-paren-baren-yield.rs +ui/lint/unused/issue-81314-unused-span-ident.rs +ui/lint/unused/issue-85913.rs +ui/lint/unused/issue-88519-unused-paren.rs +ui/lint/unused/issue-90807-unused-paren-error.rs +ui/lint/unused/issue-90807-unused-paren.rs +ui/lint/unused/issue-92751.rs +ui/lint/unused/issue-96606.rs +ui/lint/use-redundant/issue-92904.rs +ui/loops/issue-1962.rs +ui/loops/issue-1974.rs +ui/loops/issue-43162.rs +ui/loops/issue-50576.rs +ui/loops/issue-69225-SCEVAddExpr-wrap-flag.rs +ui/loops/issue-69225-layout-repeated-checked-add.rs +ui/loops/issue-82916.rs +ui/lowering/issue-121108.rs +ui/lowering/issue-96847.rs +ui/lto/issue-100772.rs +ui/lto/issue-105637.rs +ui/lto/issue-11154.rs +ui/macros/auxiliary/issue-100199.rs +ui/macros/auxiliary/issue-19163.rs +ui/macros/auxiliary/issue-40469.rs +ui/macros/auxiliary/issue-75982.rs +ui/macros/issue-100199.rs +ui/macros/issue-102878.rs +ui/macros/issue-103529.rs +ui/macros/issue-104769-concat_bytes-invalid-literal.rs +ui/macros/issue-105011.rs +ui/macros/issue-10536.rs +ui/macros/issue-106837.rs +ui/macros/issue-109237.rs +ui/macros/issue-111749.rs +ui/macros/issue-112342-1.rs +ui/macros/issue-112342-2.rs +ui/macros/issue-118048.rs +ui/macros/issue-118786.rs +ui/macros/issue-16098.rs +ui/macros/issue-19163.rs +ui/macros/issue-21356.rs +ui/macros/issue-22463.rs +ui/macros/issue-25274.rs +ui/macros/issue-25385.rs +ui/macros/issue-26094.rs +ui/macros/issue-26322.rs +ui/macros/issue-2804-2.rs +ui/macros/issue-2804.rs +ui/macros/issue-29084.rs +ui/macros/issue-30007.rs +ui/macros/issue-30143.rs +ui/macros/issue-33185.rs +ui/macros/issue-34171.rs +ui/macros/issue-34421-mac-expr-bad-stmt-good-add-semi.rs +ui/macros/issue-35450.rs +ui/macros/issue-37175.rs +ui/macros/issue-38715.rs +ui/macros/issue-39388.rs +ui/macros/issue-39404.rs +ui/macros/issue-39467.rs +ui/macros/issue-40469.rs +ui/macros/issue-40770.rs +ui/macros/issue-41776.rs +ui/macros/issue-41803.rs +ui/macros/issue-42954.rs +ui/macros/issue-44127.rs +ui/macros/issue-46438.rs +ui/macros/issue-5060.rs +ui/macros/issue-51848.rs +ui/macros/issue-52169.rs +ui/macros/issue-54441.rs +ui/macros/issue-57597.rs +ui/macros/issue-58490.rs +ui/macros/issue-61033-1.rs +ui/macros/issue-61033-2.rs +ui/macros/issue-61053-different-kleene.rs +ui/macros/issue-61053-duplicate-binder.rs +ui/macros/issue-61053-missing-repetition.rs +ui/macros/issue-61053-unbound.rs +ui/macros/issue-63102.rs +ui/macros/issue-6596-1.rs +ui/macros/issue-6596-2.rs +ui/macros/issue-68058.rs +ui/macros/issue-68060.rs +ui/macros/issue-69396-const-no-type-in-macro.rs +ui/macros/issue-69838-mods-relative-to-included-path.rs +ui/macros/issue-70446.rs +ui/macros/issue-75982-foreign-macro-weird-mod.rs +ui/macros/issue-77475.rs +ui/macros/issue-78325-inconsistent-resolution.rs +ui/macros/issue-78333.rs +ui/macros/issue-78892-substitution-in-statement-attr.rs +ui/macros/issue-81006.rs +ui/macros/issue-83340.rs +ui/macros/issue-83344.rs +ui/macros/issue-84195-lint-anon-const.rs +ui/macros/issue-84429-matches-edition.rs +ui/macros/issue-84632-eager-expansion-recursion-limit.rs +ui/macros/issue-86082-option-env-invalid-char.rs +ui/macros/issue-86865.rs +ui/macros/issue-8709.rs +ui/macros/issue-87877.rs +ui/macros/issue-88206.rs +ui/macros/issue-88228.rs +ui/macros/issue-8851.rs +ui/macros/issue-92267.rs +ui/macros/issue-95267.rs +ui/macros/issue-95533.rs +ui/macros/issue-98466-allow.rs +ui/macros/issue-98466.rs +ui/macros/issue-98790.rs +ui/macros/issue-99261.rs +ui/macros/issue-99265.rs +ui/macros/issue-99907.rs +ui/macros/rfc-3086-metavar-expr/issue-111904.rs +ui/malformed/issue-107423-unused-delim-only-one-no-pair.rs +ui/malformed/issue-69341-malformed-derive-inert.rs +ui/marker_trait_attr/issue-61651-type-mismatch.rs +ui/match/issue-112438.rs +ui/match/issue-113012.rs +ui/match/issue-11319.rs +ui/match/issue-114691.rs +ui/match/issue-115681.rs +ui/match/issue-11940.rs +ui/match/issue-12552.rs +ui/match/issue-18060.rs +ui/match/issue-26251.rs +ui/match/issue-26996.rs +ui/match/issue-27021.rs +ui/match/issue-33498.rs +ui/match/issue-36401.rs +ui/match/issue-37598.rs +ui/match/issue-42679.rs +ui/match/issue-46920-byte-array-patterns.rs +ui/match/issue-5530.rs +ui/match/issue-56685.rs +ui/match/issue-70972-dyn-trait.rs +ui/match/issue-72680.rs +ui/match/issue-72896-non-partial-eq-const.rs +ui/match/issue-74050-end-span.rs +ui/match/issue-82392.rs +ui/match/issue-82866.rs +ui/match/issue-84434.rs +ui/match/issue-91058.rs +ui/match/issue-92100.rs +ui/methods/issue-19521.rs +ui/methods/issue-3707.rs +ui/methods/issue-7950.rs +ui/methods/issues/issue-105732.rs +ui/methods/issues/issue-61525.rs +ui/methods/issues/issue-84495.rs +ui/methods/issues/issue-90315.rs +ui/methods/issues/issue-94581.rs +ui/mir/auxiliary/issue_76375_aux.rs +ui/mir/issue-101844.rs +ui/mir/issue-102389.rs +ui/mir/issue-105809.rs +ui/mir/issue-106062.rs +ui/mir/issue-107678-projection-with-lifetime.rs +ui/mir/issue-107691.rs +ui/mir/issue-109004-drop-large-array.rs +ui/mir/issue-109743.rs +ui/mir/issue-112269.rs +ui/mir/issue-121103.rs +ui/mir/issue-29227.rs +ui/mir/issue-46845.rs +ui/mir/issue-60390.rs +ui/mir/issue-66851.rs +ui/mir/issue-66930.rs +ui/mir/issue-67639-normalization-ice.rs +ui/mir/issue-67710-inline-projection.rs +ui/mir/issue-67947.rs +ui/mir/issue-68841.rs +ui/mir/issue-71793-inline-args-storage.rs +ui/mir/issue-73914.rs +ui/mir/issue-74739.rs +ui/mir/issue-75053.rs +ui/mir/issue-75419-validation-impl-trait.rs +ui/mir/issue-76248.rs +ui/mir/issue-76375.rs +ui/mir/issue-76740-copy-propagation.rs +ui/mir/issue-76803-branches-not-same.rs +ui/mir/issue-77002.rs +ui/mir/issue-77359-simplify-arm-identity.rs +ui/mir/issue-77911.rs +ui/mir/issue-78496.rs +ui/mir/issue-80949.rs +ui/mir/issue-83499-input-output-iteration-ice.rs +ui/mir/issue-89485.rs +ui/mir/issue-91745.rs +ui/mir/issue-92893.rs +ui/mir/issue-99852.rs +ui/mir/issue-99866.rs +ui/mir/issue66339.rs +ui/mir/validate/issue-95978-validator-lifetime-comparison.rs +ui/mismatched_types/issue-106182.rs +ui/mismatched_types/issue-112036.rs +ui/mismatched_types/issue-118145-unwrap-for-shorthand.rs +ui/mismatched_types/issue-118510.rs +ui/mismatched_types/issue-13033.rs +ui/mismatched_types/issue-1362.rs +ui/mismatched_types/issue-1448-2.rs +ui/mismatched_types/issue-19109.rs +ui/mismatched_types/issue-26480.rs +ui/mismatched_types/issue-35030.rs +ui/mismatched_types/issue-36053-2.rs +ui/mismatched_types/issue-38371-unfixable.rs +ui/mismatched_types/issue-38371.rs +ui/mismatched_types/issue-47706-trait.rs +ui/mismatched_types/issue-47706.rs +ui/mismatched_types/issue-74918-missing-lifetime.rs +ui/mismatched_types/issue-75361-mismatched-impl.rs +ui/mismatched_types/issue-84976.rs +ui/missing-trait-bounds/auxiliary/issue-69725.rs +ui/missing-trait-bounds/issue-35677.rs +ui/missing-trait-bounds/issue-69725.rs +ui/modules/auxiliary/issue-13872-1.rs +ui/modules/auxiliary/issue-13872-2.rs +ui/modules/auxiliary/issue-13872-3.rs +ui/modules/auxiliary/issue-1920.rs +ui/modules/issue-107649.rs +ui/modules/issue-13872.rs +ui/modules/issue-1920-1.rs +ui/modules/issue-1920-2.rs +ui/modules/issue-1920-3.rs +ui/modules/issue-56411-aux.rs +ui/modules/issue-56411.rs +ui/moves/issue-22536-copy-mustnt-zero.rs +ui/moves/issue-34721.rs +ui/moves/issue-46099-move-in-macro.rs +ui/moves/issue-72649-uninit-in-loop.rs +ui/moves/issue-75904-move-closure-loop.rs +ui/moves/issue-99470-move-out-of-some.rs +ui/never_type/issue-10176.rs +ui/never_type/issue-13352.rs +ui/never_type/issue-2149.rs +ui/never_type/issue-44402.rs +ui/never_type/issue-51506.rs +ui/never_type/issue-52443.rs +ui/never_type/issue-5500-1.rs +ui/never_type/issue-96335.rs +ui/nll/closure-requirements/issue-58127-mutliple-requirements.rs +ui/nll/issue-112604-closure-output-normalize.rs +ui/nll/issue-16223.rs +ui/nll/issue-21114-ebfull.rs +ui/nll/issue-21114-kixunil.rs +ui/nll/issue-21232-partial-init-and-erroneous-use.rs +ui/nll/issue-21232-partial-init-and-use.rs +ui/nll/issue-22323-temp-destruction.rs +ui/nll/issue-24535-allow-mutable-borrow-in-match-guard.rs +ui/nll/issue-27282-move-match-input-into-guard.rs +ui/nll/issue-27282-move-ref-mut-into-guard.rs +ui/nll/issue-27282-mutate-before-diverging-arm-1.rs +ui/nll/issue-27282-mutate-before-diverging-arm-2.rs +ui/nll/issue-27282-mutate-before-diverging-arm-3.rs +ui/nll/issue-27282-mutation-in-guard.rs +ui/nll/issue-27282-reborrow-ref-mut-in-guard.rs +ui/nll/issue-27583.rs +ui/nll/issue-27868.rs +ui/nll/issue-30104.rs +ui/nll/issue-30438-a.rs +ui/nll/issue-30438-b.rs +ui/nll/issue-30438-c.rs +ui/nll/issue-31567.rs +ui/nll/issue-32382-index-assoc-type-with-lifetime.rs +ui/nll/issue-40510-1.rs +ui/nll/issue-40510-2.rs +ui/nll/issue-40510-3.rs +ui/nll/issue-40510-4.rs +ui/nll/issue-42574-diagnostic-in-nested-closure.rs +ui/nll/issue-43058.rs +ui/nll/issue-45157.rs +ui/nll/issue-45696-long-live-borrows-in-boxes.rs +ui/nll/issue-45696-no-variant-box-recur.rs +ui/nll/issue-45696-scribble-on-boxed-borrow.rs +ui/nll/issue-46023.rs +ui/nll/issue-46036.rs +ui/nll/issue-46589.rs +ui/nll/issue-47022.rs +ui/nll/issue-47153-generic-const.rs +ui/nll/issue-47388.rs +ui/nll/issue-47470.rs +ui/nll/issue-47589.rs +ui/nll/issue-48070.rs +ui/nll/issue-48179.rs +ui/nll/issue-48238.rs +ui/nll/issue-48623-closure.rs +ui/nll/issue-48623-coroutine.rs +ui/nll/issue-48697.rs +ui/nll/issue-48803.rs +ui/nll/issue-50343.rs +ui/nll/issue-50461-used-mut-from-moves.rs +ui/nll/issue-50716-1.rs +ui/nll/issue-50716.rs +ui/nll/issue-51191.rs +ui/nll/issue-51244.rs +ui/nll/issue-51268.rs +ui/nll/issue-51345-2.rs +ui/nll/issue-51351.rs +ui/nll/issue-51512.rs +ui/nll/issue-51770.rs +ui/nll/issue-52057.rs +ui/nll/issue-52059-report-when-borrow-and-drop-conflict.rs +ui/nll/issue-52078.rs +ui/nll/issue-52086.rs +ui/nll/issue-52113.rs +ui/nll/issue-52213.rs +ui/nll/issue-52533-1.rs +ui/nll/issue-52534-1.rs +ui/nll/issue-52534-2.rs +ui/nll/issue-52534.rs +ui/nll/issue-52663-span-decl-captured-variable.rs +ui/nll/issue-52663-trait-object.rs +ui/nll/issue-52669.rs +ui/nll/issue-52742.rs +ui/nll/issue-52992.rs +ui/nll/issue-53040.rs +ui/nll/issue-53119.rs +ui/nll/issue-53123-raw-pointer-cast.rs +ui/nll/issue-53570.rs +ui/nll/issue-53773.rs +ui/nll/issue-53807.rs +ui/nll/issue-54189.rs +ui/nll/issue-54302-cases.rs +ui/nll/issue-54302.rs +ui/nll/issue-54382-use-span-of-tail-of-block.rs +ui/nll/issue-54556-niconii.rs +ui/nll/issue-54556-stephaneyfx.rs +ui/nll/issue-54556-temps-in-tail-diagnostic.rs +ui/nll/issue-54556-used-vs-unused-tails.rs +ui/nll/issue-54556-wrap-it-up.rs +ui/nll/issue-54779-anon-static-lifetime.rs +ui/nll/issue-54943-3.rs +ui/nll/issue-54943.rs +ui/nll/issue-55288.rs +ui/nll/issue-55344.rs +ui/nll/issue-55394.rs +ui/nll/issue-55401.rs +ui/nll/issue-55511.rs +ui/nll/issue-55651.rs +ui/nll/issue-55825-const-fn.rs +ui/nll/issue-55850.rs +ui/nll/issue-57100.rs +ui/nll/issue-57265-return-type-wf-check.rs +ui/nll/issue-57280-1-flipped.rs +ui/nll/issue-57280-1.rs +ui/nll/issue-57280.rs +ui/nll/issue-57642-higher-ranked-subtype.rs +ui/nll/issue-57843.rs +ui/nll/issue-57960.rs +ui/nll/issue-57989.rs +ui/nll/issue-58053.rs +ui/nll/issue-58299.rs +ui/nll/issue-61311-normalize.rs +ui/nll/issue-61320-normalize.rs +ui/nll/issue-61424.rs +ui/nll/issue-62007-assign-const-index.rs +ui/nll/issue-62007-assign-differing-fields.rs +ui/nll/issue-63154-normalize.rs +ui/nll/issue-67007-escaping-data.rs +ui/nll/issue-68550.rs +ui/nll/issue-69114-static-mut-ty.rs +ui/nll/issue-69114-static-ty.rs +ui/nll/issue-73159-rpit-static.rs +ui/nll/issue-75777.rs +ui/nll/issue-78561.rs +ui/nll/issue-95272.rs +ui/nll/issue-97997.rs +ui/nll/issue-98170.rs +ui/nll/issue-98589-closures-relate-named-regions.rs +ui/nll/issue-98693.rs +ui/nll/polonius/issue-46589.rs +ui/nll/relate_tys/issue-48071.rs +ui/nll/ty-outlives/issue-53789-1.rs +ui/nll/ty-outlives/issue-53789-2.rs +ui/nll/ty-outlives/issue-55756.rs +ui/nll/user-annotations/issue-54124.rs +ui/nll/user-annotations/issue-54570-bootstrapping.rs +ui/nll/user-annotations/issue-55219.rs +ui/nll/user-annotations/issue-55241.rs +ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs +ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs +ui/numbers-arithmetic/issue-105626.rs +ui/numbers-arithmetic/issue-8460.rs +ui/object-safety/issue-102762.rs +ui/object-safety/issue-102933.rs +ui/object-safety/issue-106247.rs +ui/object-safety/issue-19538.rs +ui/on-unimplemented/issue-104140.rs +ui/or-patterns/issue-64879-trailing-before-guard.rs +ui/or-patterns/issue-67514-irrefutable-param.rs +ui/or-patterns/issue-68785-irrefutable-param-with-at.rs +ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs +ui/or-patterns/issue-69875-should-have-been-expanded-earlier.rs +ui/or-patterns/issue-70413-no-unreachable-pat-and-guard.rs +ui/overloaded/issue-14958.rs +ui/packed/issue-118537-field-offset-ice.rs +ui/packed/issue-118537-field-offset.rs +ui/packed/issue-27060-2.rs +ui/packed/issue-27060.rs +ui/packed/issue-46152.rs +ui/panics/issue-47429-short-backtraces.rs +ui/parser/issue-116781.rs +ui/parser/issues/auxiliary/issue-21146-inc.rs +ui/parser/issues/auxiliary/issue-89971-outer-attr-following-inner-attr-ice.rs +ui/parser/issues/auxiliary/issue-94340-inc.rs +ui/parser/issues/issue-100197-mut-let.rs +ui/parser/issues/issue-101477-enum.rs +ui/parser/issues/issue-101477-let.rs +ui/parser/issues/issue-101540.rs +ui/parser/issues/issue-102182-impl-trait-recover.rs +ui/parser/issues/issue-102806.rs +ui/parser/issues/issue-103143.rs +ui/parser/issues/issue-103381.rs +ui/parser/issues/issue-103425.rs +ui/parser/issues/issue-103451.rs +ui/parser/issues/issue-103748-ICE-wrong-braces.rs +ui/parser/issues/issue-10392-2.rs +ui/parser/issues/issue-10392.rs +ui/parser/issues/issue-104367.rs +ui/parser/issues/issue-104620.rs +ui/parser/issues/issue-104867-inc-dec-2.rs +ui/parser/issues/issue-104867-inc-dec.rs +ui/parser/issues/issue-105209.rs +ui/parser/issues/issue-105366.rs +ui/parser/issues/issue-105634.rs +ui/parser/issues/issue-10636-1.rs +ui/parser/issues/issue-10636-2.rs +ui/parser/issues/issue-107705.rs +ui/parser/issues/issue-108109-fn-missing-params.rs +ui/parser/issues/issue-108109-fn-trait-missing-paren.rs +ui/parser/issues/issue-108242-semicolon-recovery.rs +ui/parser/issues/issue-108495-dec.rs +ui/parser/issues/issue-110014.rs +ui/parser/issues/issue-111148.rs +ui/parser/issues/issue-111416.rs +ui/parser/issues/issue-111692.rs +ui/parser/issues/issue-112188.rs +ui/parser/issues/issue-112458.rs +ui/parser/issues/issue-113110-non-item-at-module-root.rs +ui/parser/issues/issue-113203.rs +ui/parser/issues/issue-113342.rs +ui/parser/issues/issue-114219.rs +ui/parser/issues/issue-115780-pat-lt-bracket-in-macro-call.rs +ui/parser/issues/issue-118530-ice.rs +ui/parser/issues/issue-118531-ice.rs +ui/parser/issues/issue-13483.rs +ui/parser/issues/issue-14303-fncall.rs +ui/parser/issues/issue-14303.rs +ui/parser/issues/issue-15914.rs +ui/parser/issues/issue-15980.rs +ui/parser/issues/issue-1655.rs +ui/parser/issues/issue-17718-const-mut.rs +ui/parser/issues/issue-17718-parse-const.rs +ui/parser/issues/issue-17904-2.rs +ui/parser/issues/issue-17904.rs +ui/parser/issues/issue-1802-1.rs +ui/parser/issues/issue-1802-2.rs +ui/parser/issues/issue-19096.rs +ui/parser/issues/issue-19398.rs +ui/parser/issues/issue-20616-1.rs +ui/parser/issues/issue-20616-2.rs +ui/parser/issues/issue-20616-3.rs +ui/parser/issues/issue-20616-4.rs +ui/parser/issues/issue-20616-5.rs +ui/parser/issues/issue-20616-6.rs +ui/parser/issues/issue-20616-7.rs +ui/parser/issues/issue-20616-8.rs +ui/parser/issues/issue-20616-9.rs +ui/parser/issues/issue-20711-2.rs +ui/parser/issues/issue-20711.rs +ui/parser/issues/issue-21146.rs +ui/parser/issues/issue-21153.rs +ui/parser/issues/issue-21475.rs +ui/parser/issues/issue-22647.rs +ui/parser/issues/issue-22712.rs +ui/parser/issues/issue-2354-1.rs +ui/parser/issues/issue-2354.rs +ui/parser/issues/issue-23620-invalid-escapes.rs +ui/parser/issues/issue-24197.rs +ui/parser/issues/issue-24375.rs +ui/parser/issues/issue-24780.rs +ui/parser/issues/issue-27255.rs +ui/parser/issues/issue-30318.rs +ui/parser/issues/issue-3036.rs +ui/parser/issues/issue-31804.rs +ui/parser/issues/issue-32214.rs +ui/parser/issues/issue-32446.rs +ui/parser/issues/issue-32501.rs +ui/parser/issues/issue-32505.rs +ui/parser/issues/issue-33262.rs +ui/parser/issues/issue-33413.rs +ui/parser/issues/issue-33418.rs +ui/parser/issues/issue-33455.rs +ui/parser/issues/issue-34222-1.rs +ui/parser/issues/issue-34255-1.rs +ui/parser/issues/issue-35813-postfix-after-cast.rs +ui/parser/issues/issue-39616.rs +ui/parser/issues/issue-41155.rs +ui/parser/issues/issue-43196.rs +ui/parser/issues/issue-43692.rs +ui/parser/issues/issue-44021.rs +ui/parser/issues/issue-44406.rs +ui/parser/issues/issue-45296.rs +ui/parser/issues/issue-46186.rs +ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items-bad-variants.rs +ui/parser/issues/issue-48137-macros-cannot-interpolate-impl-items.rs +ui/parser/issues/issue-48508-aux.rs +ui/parser/issues/issue-48508.rs +ui/parser/issues/issue-48636.rs +ui/parser/issues/issue-49040.rs +ui/parser/issues/issue-49257.rs +ui/parser/issues/issue-51602.rs +ui/parser/issues/issue-52496.rs +ui/parser/issues/issue-54521-1.rs +ui/parser/issues/issue-54521-2.rs +ui/parser/issues/issue-54521-3.rs +ui/parser/issues/issue-5544-a.rs +ui/parser/issues/issue-5544-b.rs +ui/parser/issues/issue-56031.rs +ui/parser/issues/issue-57198.rs +ui/parser/issues/issue-57684.rs +ui/parser/issues/issue-57819.rs +ui/parser/issues/issue-5806.rs +ui/parser/issues/issue-58094-missing-right-square-bracket.rs +ui/parser/issues/issue-58856-1.rs +ui/parser/issues/issue-58856-2.rs +ui/parser/issues/issue-59418.rs +ui/parser/issues/issue-60075.rs +ui/parser/issues/issue-61858.rs +ui/parser/issues/issue-62524.rs +ui/parser/issues/issue-62546.rs +ui/parser/issues/issue-62554.rs +ui/parser/issues/issue-62660.rs +ui/parser/issues/issue-62881.rs +ui/parser/issues/issue-62894.rs +ui/parser/issues/issue-62895.rs +ui/parser/issues/issue-62913.rs +ui/parser/issues/issue-62973.rs +ui/parser/issues/issue-63115-range-pat-interpolated.rs +ui/parser/issues/issue-63116.rs +ui/parser/issues/issue-63135.rs +ui/parser/issues/issue-64732.rs +ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs +ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs +ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.rs +ui/parser/issues/issue-65257-invalid-var-decl-recovery.rs +ui/parser/issues/issue-65846-rollback-gating-failing-matcher.rs +ui/parser/issues/issue-6610.rs +ui/parser/issues/issue-66357-unexpected-unreachable.rs +ui/parser/issues/issue-66473.rs +ui/parser/issues/issue-67146-negative-outlives-bound-syntactic-fail.rs +ui/parser/issues/issue-67377-invalid-syntax-in-enum-discriminant.rs +ui/parser/issues/issue-68000-unicode-ident-after-missing-comma.rs +ui/parser/issues/issue-68091-unicode-ident-after-if.rs +ui/parser/issues/issue-68092-unicode-ident-after-incomplete-expr.rs +ui/parser/issues/issue-68629.rs +ui/parser/issues/issue-68730.rs +ui/parser/issues/issue-68788-in-trait-item-propagation.rs +ui/parser/issues/issue-68890-2.rs +ui/parser/issues/issue-68890.rs +ui/parser/issues/issue-68987-unmatch-issue-1.rs +ui/parser/issues/issue-68987-unmatch-issue-2.rs +ui/parser/issues/issue-68987-unmatch-issue-3.rs +ui/parser/issues/issue-68987-unmatch-issue.rs +ui/parser/issues/issue-69259.rs +ui/parser/issues/issue-70050-ntliteral-accepts-negated-lit.rs +ui/parser/issues/issue-70388-recover-dotdotdot-rest-pat.rs +ui/parser/issues/issue-70388-without-witness.rs +ui/parser/issues/issue-70549-resolve-after-recovered-self-ctor.rs +ui/parser/issues/issue-70552-ascription-in-parens-after-call.rs +ui/parser/issues/issue-70583-block-is-empty-1.rs +ui/parser/issues/issue-70583-block-is-empty-2.rs +ui/parser/issues/issue-7222.rs +ui/parser/issues/issue-72253.rs +ui/parser/issues/issue-72373.rs +ui/parser/issues/issue-73568-lifetime-after-mut.rs +ui/parser/issues/issue-75599.rs +ui/parser/issues/issue-76437-async.rs +ui/parser/issues/issue-76437-const-async-unsafe.rs +ui/parser/issues/issue-76437-const-async.rs +ui/parser/issues/issue-76437-const.rs +ui/parser/issues/issue-76437-pub-crate-unsafe.rs +ui/parser/issues/issue-76437-unsafe.rs +ui/parser/issues/issue-76597.rs +ui/parser/issues/issue-7970b.rs +ui/parser/issues/issue-81804.rs +ui/parser/issues/issue-81806.rs +ui/parser/issues/issue-81827.rs +ui/parser/issues/issue-83639.rs +ui/parser/issues/issue-84104.rs +ui/parser/issues/issue-84117.rs +ui/parser/issues/issue-84148-1.rs +ui/parser/issues/issue-84148-2.rs +ui/parser/issues/issue-8537.rs +ui/parser/issues/issue-86895.rs +ui/parser/issues/issue-87086-colon-path-sep.rs +ui/parser/issues/issue-87197-missing-semicolon.rs +ui/parser/issues/issue-87635.rs +ui/parser/issues/issue-87694-duplicated-pub.rs +ui/parser/issues/issue-87694-misplaced-pub.rs +ui/parser/issues/issue-87812-path.rs +ui/parser/issues/issue-87812.rs +ui/parser/issues/issue-88276-unary-plus.rs +ui/parser/issues/issue-88583-union-as-ident.rs +ui/parser/issues/issue-88770.rs +ui/parser/issues/issue-88818.rs +ui/parser/issues/issue-89388.rs +ui/parser/issues/issue-89396.rs +ui/parser/issues/issue-89574.rs +ui/parser/issues/issue-89971-outer-attr-following-inner-attr-ice.rs +ui/parser/issues/issue-90728.rs +ui/parser/issues/issue-90993.rs +ui/parser/issues/issue-91421.rs +ui/parser/issues/issue-91461.rs +ui/parser/issues/issue-93282.rs +ui/parser/issues/issue-93867.rs +ui/parser/issues/issue-94340.rs +ui/parser/issues/issue-98601-delimiter-error-1.rs +ui/parser/issues/issue-98601-delimiter-error-unexpected-close.rs +ui/parser/issues/issue-99625-enum-struct-mutually-exclusive.rs +ui/parser/issues/issue-99910-const-let-mutually-exclusive.rs +ui/parser/macro/issue-33569.rs +ui/parser/macro/issue-37113.rs +ui/parser/macro/issue-37234.rs +ui/parser/raw/issue-70677-panic-on-unterminated-raw-str-at-eof.rs +ui/parser/shebang/issue-71471-ignore-tidy.rs +ui/pattern/issue-10392.rs +ui/pattern/issue-106552.rs +ui/pattern/issue-106862.rs +ui/pattern/issue-110508.rs +ui/pattern/issue-115599.rs +ui/pattern/issue-11577.rs +ui/pattern/issue-117626.rs +ui/pattern/issue-12582.rs +ui/pattern/issue-14221.rs +ui/pattern/issue-15080.rs +ui/pattern/issue-17718-patterns.rs +ui/pattern/issue-22546.rs +ui/pattern/issue-27320.rs +ui/pattern/issue-28992-empty.rs +ui/pattern/issue-52240.rs +ui/pattern/issue-6449.rs +ui/pattern/issue-66270-pat-struct-parser-recovery.rs +ui/pattern/issue-67037-pat-tup-scrut-ty-diff-less-fields.rs +ui/pattern/issue-67776-match-same-name-enum-variant-refs.rs +ui/pattern/issue-68393-let-pat-assoc-constant.rs +ui/pattern/issue-72565.rs +ui/pattern/issue-72574-1.rs +ui/pattern/issue-72574-2.rs +ui/pattern/issue-74539.rs +ui/pattern/issue-74702.rs +ui/pattern/issue-74954.rs +ui/pattern/issue-80186-mut-binding-help-suggestion.rs +ui/pattern/issue-8351-1.rs +ui/pattern/issue-8351-2.rs +ui/pattern/issue-88074-pat-range-type-inference-err.rs +ui/pattern/issue-88074-pat-range-type-inference.rs +ui/pattern/issue-92074-macro-ice.rs +ui/pattern/issue-94866.rs +ui/pattern/issue-95878.rs +ui/pattern/move-ref-patterns/issue-53840.rs +ui/pattern/usefulness/integer-ranges/issue-117648-overlapping_range_endpoints-false-positive.rs +ui/pattern/usefulness/issue-105479-str-non-exhaustiveness.rs +ui/pattern/usefulness/issue-118437-exponential-time-on-diagonal-match.rs +ui/pattern/usefulness/issue-119493-type-error-ice.rs +ui/pattern/usefulness/issue-119778-type-error-ice.rs +ui/pattern/usefulness/issue-12116.rs +ui/pattern/usefulness/issue-12369.rs +ui/pattern/usefulness/issue-13727.rs +ui/pattern/usefulness/issue-15129.rs +ui/pattern/usefulness/issue-2111.rs +ui/pattern/usefulness/issue-30240-b.rs +ui/pattern/usefulness/issue-30240-rpass.rs +ui/pattern/usefulness/issue-30240.rs +ui/pattern/usefulness/issue-3096-1.rs +ui/pattern/usefulness/issue-3096-2.rs +ui/pattern/usefulness/issue-31221.rs +ui/pattern/usefulness/issue-31561.rs +ui/pattern/usefulness/issue-35609.rs +ui/pattern/usefulness/issue-3601.rs +ui/pattern/usefulness/issue-39362.rs +ui/pattern/usefulness/issue-40221.rs +ui/pattern/usefulness/issue-4321.rs +ui/pattern/usefulness/issue-50900.rs +ui/pattern/usefulness/issue-53820-slice-pattern-large-array.rs +ui/pattern/usefulness/issue-56379.rs +ui/pattern/usefulness/issue-57472.rs +ui/pattern/usefulness/issue-65413-constants-and-slices-exhaustiveness.rs +ui/pattern/usefulness/issue-66501.rs +ui/pattern/usefulness/issue-71930-type-of-match-scrutinee.rs +ui/pattern/usefulness/issue-72377.rs +ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs +ui/pattern/usefulness/issue-78123-non-exhaustive-reference.rs +ui/pattern/usefulness/issue-78549-ref-pat-and-str.rs +ui/pattern/usefulness/issue-80501-or-pat-and-macro.rs +ui/pattern/usefulness/issue-82772-match-box-as-struct.rs +ui/pattern/usefulness/issue-85222-types-containing-non-exhaustive-types.rs +ui/pattern/usefulness/issue-88747.rs +ui/polymorphization/issue-74614.rs +ui/polymorphization/issue-74636.rs +ui/privacy/auxiliary/issue-117997.rs +ui/privacy/auxiliary/issue-119463-extern.rs +ui/privacy/auxiliary/issue-17718-const-privacy.rs +ui/privacy/auxiliary/issue-57264-1.rs +ui/privacy/auxiliary/issue-57264-2.rs +ui/privacy/auxiliary/issue-75907.rs +ui/privacy/auxiliary/issue-92755.rs +ui/privacy/issue-111220-2-tuple-struct-fields-projection.rs +ui/privacy/issue-111220-tuple-struct-fields.rs +ui/privacy/issue-113860-1.rs +ui/privacy/issue-113860-2.rs +ui/privacy/issue-113860.rs +ui/privacy/issue-11593.rs +ui/privacy/issue-117997.rs +ui/privacy/issue-119463.rs +ui/privacy/issue-13641.rs +ui/privacy/issue-17718-const-privacy.rs +ui/privacy/issue-29161.rs +ui/privacy/issue-30079.rs +ui/privacy/issue-46209-private-enum-variant-reexport.rs +ui/privacy/issue-57264-1.rs +ui/privacy/issue-57264-2.rs +ui/privacy/issue-75062-fieldless-tuple-struct.rs +ui/privacy/issue-75906.rs +ui/privacy/issue-75907.rs +ui/privacy/issue-75907_b.rs +ui/privacy/issue-79593.rs +ui/privacy/issue-92755.rs +ui/proc-macro/auxiliary/issue-104884.rs +ui/proc-macro/auxiliary/issue-107113.rs +ui/proc-macro/auxiliary/issue-118809.rs +ui/proc-macro/auxiliary/issue-38586.rs +ui/proc-macro/auxiliary/issue-39889.rs +ui/proc-macro/auxiliary/issue-42708.rs +ui/proc-macro/auxiliary/issue-50061.rs +ui/proc-macro/auxiliary/issue-50493.rs +ui/proc-macro/auxiliary/issue-59191.rs +ui/proc-macro/auxiliary/issue-66286.rs +ui/proc-macro/auxiliary/issue-75801.rs +ui/proc-macro/auxiliary/issue-79242.rs +ui/proc-macro/auxiliary/issue-79825.rs +ui/proc-macro/auxiliary/issue-83510.rs +ui/proc-macro/auxiliary/issue-91800-macro.rs +ui/proc-macro/issue-104884-trait-impl-sugg-err.rs +ui/proc-macro/issue-107113-wrap.rs +ui/proc-macro/issue-118455-skip-err-builtin.rs +ui/proc-macro/issue-118809.rs +ui/proc-macro/issue-36935.rs +ui/proc-macro/issue-37788.rs +ui/proc-macro/issue-38586.rs +ui/proc-macro/issue-39889.rs +ui/proc-macro/issue-42708.rs +ui/proc-macro/issue-50061.rs +ui/proc-macro/issue-50493.rs +ui/proc-macro/issue-53481.rs +ui/proc-macro/issue-59191-replace-root-with-fn.rs +ui/proc-macro/issue-66286.rs +ui/proc-macro/issue-73933-procedural-masquerade.rs +ui/proc-macro/issue-75734-pp-paren.rs +ui/proc-macro/issue-75801.rs +ui/proc-macro/issue-75930-derive-cfg.rs +ui/proc-macro/issue-76182-leading-vert-pat.rs +ui/proc-macro/issue-76270-panic-in-libproc-macro.rs +ui/proc-macro/issue-78675-captured-inner-attrs.rs +ui/proc-macro/issue-79148.rs +ui/proc-macro/issue-79242-slow-retokenize-check.rs +ui/proc-macro/issue-79825.rs +ui/proc-macro/issue-80760-empty-stmt.rs +ui/proc-macro/issue-81007-item-attrs.rs +ui/proc-macro/issue-81543-item-parse-err.rs +ui/proc-macro/issue-81555.rs +ui/proc-macro/issue-83469-global-alloc-invalid-stmt.rs +ui/proc-macro/issue-83510.rs +ui/proc-macro/issue-86781-bad-inner-doc.rs +ui/proc-macro/issue-89566-suggest-fix-invalid-top-level-macro-attr.rs +ui/proc-macro/issue-91800.rs +ui/process/issue-13304.rs +ui/process/issue-14456.rs +ui/process/issue-14940.rs +ui/process/issue-16272.rs +ui/process/issue-20091.rs +ui/process/issue-30490.rs +ui/ptr_ops/issue-80309-safe.rs +ui/ptr_ops/issue-80309.rs +ui/pub/issue-33174-restricted-type-in-public-interface.rs +ui/query-system/issue-83479.rs +ui/range/issue-54505-no-literals.rs +ui/range/issue-54505-no-std.rs +ui/range/issue-54505.rs +ui/range/issue-73553-misinterp-range-literal.rs +ui/reachable/auxiliary/issue-11225-1.rs +ui/reachable/auxiliary/issue-11225-2.rs +ui/reachable/auxiliary/issue-11225-3.rs +ui/reachable/issue-11225-1.rs +ui/reachable/issue-11225-2.rs +ui/reachable/issue-11225-3.rs +ui/reachable/issue-948.rs +ui/recursion/issue-23302-1.rs +ui/recursion/issue-23302-2.rs +ui/recursion/issue-23302-3.rs +ui/recursion/issue-26548-recursion-via-normalize.rs +ui/recursion/issue-38591-non-regular-dropck-recursion.rs +ui/recursion/issue-83150.rs +ui/recursion/issue-86784.rs +ui/recursion/issue-95134.rs +ui/recursion_limit/issue-105700.rs +ui/recursion_limit/issue-40003.rs +ui/regions/issue-101280.rs +ui/regions/issue-102374.rs +ui/regions/issue-102392.rs +ui/regions/issue-11612.rs +ui/regions/issue-12470.rs +ui/regions/issue-21520.rs +ui/regions/issue-24085.rs +ui/regions/issue-26448-1.rs +ui/regions/issue-26448-2.rs +ui/regions/issue-26448-3.rs +ui/regions/issue-28848.rs +ui/regions/issue-5243.rs +ui/regions/issue-56537-closure-uses-region-from-container.rs +ui/regions/issue-6157.rs +ui/regions/issue-72051-member-region-hang.rs +ui/regions/issue-78262.rs +ui/repr/issue-83505-repr-simd.rs +ui/resolve/auxiliary/issue-112831-aux.rs +ui/resolve/auxiliary/issue-19452-aux.rs +ui/resolve/auxiliary/issue-21221-3.rs +ui/resolve/auxiliary/issue-21221-4.rs +ui/resolve/auxiliary/issue-30535.rs +ui/resolve/auxiliary/issue-3907.rs +ui/resolve/auxiliary/issue-80079.rs +ui/resolve/issue-100365.rs +ui/resolve/issue-101749-2.rs +ui/resolve/issue-101749.rs +ui/resolve/issue-10200.rs +ui/resolve/issue-102946.rs +ui/resolve/issue-103202.rs +ui/resolve/issue-103474.rs +ui/resolve/issue-104700-inner_scope.rs +ui/resolve/issue-105069.rs +ui/resolve/issue-107563-ambiguous-glob-reexports.rs +ui/resolve/issue-108529.rs +ui/resolve/issue-109153.rs +ui/resolve/issue-109250.rs +ui/resolve/issue-111312.rs +ui/resolve/issue-111727.rs +ui/resolve/issue-112472-multi-generics-suggestion.rs +ui/resolve/issue-113808-invalid-unused-qualifications-suggestion.rs +ui/resolve/issue-114433-invalid-unused-qualifications-suggestion.rs +ui/resolve/issue-116164.rs +ui/resolve/issue-117920.rs +ui/resolve/issue-118295.rs +ui/resolve/issue-120559.rs +ui/resolve/issue-12796.rs +ui/resolve/issue-14254.rs +ui/resolve/issue-16058.rs +ui/resolve/issue-17518.rs +ui/resolve/issue-18252.rs +ui/resolve/issue-19452.rs +ui/resolve/issue-21221-1.rs +ui/resolve/issue-21221-2.rs +ui/resolve/issue-21221-3.rs +ui/resolve/issue-21221-4.rs +ui/resolve/issue-22692.rs +ui/resolve/issue-2330.rs +ui/resolve/issue-23305.rs +ui/resolve/issue-2356.rs +ui/resolve/issue-23716.rs +ui/resolve/issue-24968.rs +ui/resolve/issue-26545.rs +ui/resolve/issue-3021-c.rs +ui/resolve/issue-3021.rs +ui/resolve/issue-30535.rs +ui/resolve/issue-3099-a.rs +ui/resolve/issue-3099-b.rs +ui/resolve/issue-31845.rs +ui/resolve/issue-33876.rs +ui/resolve/issue-35675.rs +ui/resolve/issue-3907-2.rs +ui/resolve/issue-3907.rs +ui/resolve/issue-39226.rs +ui/resolve/issue-39559-2.rs +ui/resolve/issue-39559.rs +ui/resolve/issue-42944.rs +ui/resolve/issue-49074.rs +ui/resolve/issue-5035-2.rs +ui/resolve/issue-5035.rs +ui/resolve/issue-50599.rs +ui/resolve/issue-5099.rs +ui/resolve/issue-54379.rs +ui/resolve/issue-55673.rs +ui/resolve/issue-57523.rs +ui/resolve/issue-5927.rs +ui/resolve/issue-60057.rs +ui/resolve/issue-65025-extern-static-parent-generics.rs +ui/resolve/issue-65035-static-with-parent-generics.rs +ui/resolve/issue-6642.rs +ui/resolve/issue-6702.rs +ui/resolve/issue-69401-trait-fn-no-body-ty-local.rs +ui/resolve/issue-70736-async-fn-no-body-def-collector.rs +ui/resolve/issue-73427.rs +ui/resolve/issue-80079.rs +ui/resolve/issue-81508.rs +ui/resolve/issue-82156.rs +ui/resolve/issue-82865.rs +ui/resolve/issue-85348.rs +ui/resolve/issue-85671.rs +ui/resolve/issue-88472.rs +ui/resolve/issue-90113.rs +ui/return/issue-64620.rs +ui/return/issue-82612-return-mutable-reference.rs +ui/return/issue-86188-return-not-in-fn-body.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-61188-match-slice-forbidden-without-eq.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-62307-match-ref-ref-forbidden-without-eq.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-63479-match-fnptr.rs +ui/rfcs/rfc-1445-restrict-constants-in-patterns/issue-6804-nan-match.rs +ui/rfcs/rfc-1937-termination-trait/issue-103052-1.rs +ui/rfcs/rfc-1937-termination-trait/issue-103052-2.rs +ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs +ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs +ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs +ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs +ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs +ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs +ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs +ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs +ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs +ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs +ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs +ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs +ui/rfcs/rfc-2528-type-changing-struct-update/issue-92010-trait-bound-not-satisfied.rs +ui/rfcs/rfc-2528-type-changing-struct-update/issue-96878.rs +ui/rfcs/rfc-2565-param-attrs/issue-64682-dropping-first-attrs-in-impl-fns.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-100222.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-102156.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-102985.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-103677.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-79450.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-88155.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-92111.rs +ui/rfcs/rfc-2632-const-trait-impl/issue-92230-wf-super-trait-env.rs +ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs +ui/rfcs/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +ui/rust-2018/issue-51008-1.rs +ui/rust-2018/issue-51008.rs +ui/rust-2018/issue-52202-use-suggestions.rs +ui/rust-2018/issue-54006.rs +ui/rust-2018/issue-54400-unused-extern-crate-attr-span.rs +ui/rust-2018/uniform-paths/auxiliary/issue-55779-extern-trait.rs +ui/rust-2018/uniform-paths/auxiliary/issue-56596-2.rs +ui/rust-2018/uniform-paths/auxiliary/issue-56596.rs +ui/rust-2018/uniform-paths/auxiliary/issue-87932-a.rs +ui/rust-2018/uniform-paths/issue-54253.rs +ui/rust-2018/uniform-paths/issue-55779.rs +ui/rust-2018/uniform-paths/issue-56596-2.rs +ui/rust-2018/uniform-paths/issue-56596.rs +ui/rust-2018/uniform-paths/issue-87932.rs +ui/sanitizer/issue-111184-cfi-coroutine-witness.rs +ui/sanitizer/issue-114275-cfi-const-expr-in-arry-len.rs +ui/sanitizer/issue-72154-address-lifetime-markers.rs +ui/self/issue-61882-2.rs +ui/self/issue-61882.rs +ui/simd/intrinsic/issue-85855.rs +ui/simd/issue-105439.rs +ui/simd/issue-17170.rs +ui/simd/issue-32947.rs +ui/simd/issue-39720.rs +ui/simd/issue-85915-simd-ptrs.rs +ui/simd/issue-89193.rs +ui/single-use-lifetime/issue-104440.rs +ui/single-use-lifetime/issue-107998.rs +ui/single-use-lifetime/issue-117965.rs +ui/span/issue-107353.rs +ui/span/issue-11925.rs +ui/span/issue-15480.rs +ui/span/issue-23338-locals-die-before-temps-of-body.rs +ui/span/issue-23729.rs +ui/span/issue-23827.rs +ui/span/issue-24356.rs +ui/span/issue-24690.rs +ui/span/issue-24805-dropck-child-has-items-via-parent.rs +ui/span/issue-24805-dropck-trait-has-items.rs +ui/span/issue-24895-copy-clone-dropck.rs +ui/span/issue-25199.rs +ui/span/issue-26656.rs +ui/span/issue-27522.rs +ui/span/issue-29106.rs +ui/span/issue-29595.rs +ui/span/issue-33884.rs +ui/span/issue-34264.rs +ui/span/issue-35987.rs +ui/span/issue-36537.rs +ui/span/issue-37767.rs +ui/span/issue-39018.rs +ui/span/issue-39698.rs +ui/span/issue-40157.rs +ui/span/issue-42234-unknown-receiver-type.rs +ui/span/issue-43927-non-ADT-derive.rs +ui/span/issue-71363.rs +ui/span/issue-81800.rs +ui/span/issue28498-reject-ex1.rs +ui/span/issue28498-reject-lifetime-param.rs +ui/span/issue28498-reject-passed-to-fn.rs +ui/span/issue28498-reject-trait-bound.rs +ui/specialization/issue-111232.rs +ui/specialization/issue-33017.rs +ui/specialization/issue-35376.rs +ui/specialization/issue-36804.rs +ui/specialization/issue-38091-2.rs +ui/specialization/issue-38091.rs +ui/specialization/issue-39448.rs +ui/specialization/issue-39618.rs +ui/specialization/issue-40582.rs +ui/specialization/issue-43037.rs +ui/specialization/issue-44861.rs +ui/specialization/issue-45814.rs +ui/specialization/issue-50452-fail.rs +ui/specialization/issue-50452.rs +ui/specialization/issue-51892.rs +ui/specialization/issue-52050.rs +ui/specialization/issue-59435.rs +ui/specialization/issue-63716-parse-async.rs +ui/specialization/issue-68830-spurious-diagnostics.rs +ui/specialization/issue-70442.rs +ui/specialization/min_specialization/issue-79224.rs +ui/stability-attribute/issue-106589.rs +ui/stability-attribute/issue-109177.rs +ui/stability-attribute/issue-28075.rs +ui/stability-attribute/issue-28388-3.rs +ui/stability-attribute/issue-99286-stable-intrinsics.rs +ui/static/auxiliary/issue_24843.rs +ui/static/issue-1660.rs +ui/static/issue-18118-2.rs +ui/static/issue-18118.rs +ui/static/issue-24446.rs +ui/static/issue-24843.rs +ui/static/issue-34194.rs +ui/static/issue-5216.rs +ui/statics/issue-14227.rs +ui/statics/issue-15261.rs +ui/statics/issue-17233.rs +ui/statics/issue-17718-static-sync.rs +ui/statics/issue-17718-static-unsafe-interior.rs +ui/statics/issue-44373-2.rs +ui/statics/issue-44373.rs +ui/statics/issue-91050-1.rs +ui/statics/issue-91050-2.rs +ui/std/issue-3563-3.rs +ui/std/issue-81357-unsound-file-methods.rs +ui/stdlib-unit-tests/issue-21058.rs +ui/structs-enums/enum-rec/issue-17431-6.rs +ui/structs-enums/enum-rec/issue-17431-7.rs +ui/structs-enums/issue-103869.rs +ui/structs-enums/issue-1701.rs +ui/structs-enums/issue-2718-a.rs +ui/structs-enums/issue-3008-1.rs +ui/structs-enums/issue-3008-2.rs +ui/structs-enums/issue-3008-3.rs +ui/structs-enums/issue-38002.rs +ui/structs-enums/issue-50731.rs +ui/structs-enums/struct-rec/issue-17431-1.rs +ui/structs-enums/struct-rec/issue-17431-2.rs +ui/structs-enums/struct-rec/issue-17431-3.rs +ui/structs-enums/struct-rec/issue-17431-4.rs +ui/structs-enums/struct-rec/issue-17431-5.rs +ui/structs-enums/struct-rec/issue-74224.rs +ui/structs-enums/struct-rec/issue-84611.rs +ui/structs/issue-80853.rs +ui/suggestions/auxiliary/issue-61963-1.rs +ui/suggestions/auxiliary/issue-61963.rs +ui/suggestions/auxiliary/issue-81839.rs +ui/suggestions/issue-101065.rs +ui/suggestions/issue-101421.rs +ui/suggestions/issue-101465.rs +ui/suggestions/issue-101623.rs +ui/suggestions/issue-101984.rs +ui/suggestions/issue-102354.rs +ui/suggestions/issue-102892.rs +ui/suggestions/issue-102972.rs +ui/suggestions/issue-103112.rs +ui/suggestions/issue-103646.rs +ui/suggestions/issue-104086-suggest-let.rs +ui/suggestions/issue-104287.rs +ui/suggestions/issue-104327.rs +ui/suggestions/issue-104328.rs +ui/suggestions/issue-104961.rs +ui/suggestions/issue-105226.rs +ui/suggestions/issue-105494.rs +ui/suggestions/issue-105645.rs +ui/suggestions/issue-105761-suggest-self-for-closure.rs +ui/suggestions/issue-106443-sugg-clone-for-arg.rs +ui/suggestions/issue-106443-sugg-clone-for-bound.rs +ui/suggestions/issue-107860.rs +ui/suggestions/issue-108470.rs +ui/suggestions/issue-109195.rs +ui/suggestions/issue-109291.rs +ui/suggestions/issue-109396.rs +ui/suggestions/issue-109436.rs +ui/suggestions/issue-109854.rs +ui/suggestions/issue-109991.rs +ui/suggestions/issue-112590-suggest-import.rs +ui/suggestions/issue-114701.rs +ui/suggestions/issue-114797-bad-parentheses-dyn-trait.rs +ui/suggestions/issue-116434-2015.rs +ui/suggestions/issue-116434-2021.rs +ui/suggestions/issue-117669.rs +ui/suggestions/issue-21673.rs +ui/suggestions/issue-51055-missing-semicolon-between-call-and-tuple.rs +ui/suggestions/issue-52820.rs +ui/suggestions/issue-53692.rs +ui/suggestions/issue-57672.rs +ui/suggestions/issue-59819.rs +ui/suggestions/issue-61226.rs +ui/suggestions/issue-61963.rs +ui/suggestions/issue-62843.rs +ui/suggestions/issue-64252-self-type.rs +ui/suggestions/issue-66968-suggest-sorted-words.rs +ui/suggestions/issue-68049-1.rs +ui/suggestions/issue-68049-2.rs +ui/suggestions/issue-71394-no-from-impl.rs +ui/suggestions/issue-72766.rs +ui/suggestions/issue-79843-impl-trait-with-missing-bounds-on-async-fn.rs +ui/suggestions/issue-81098.rs +ui/suggestions/issue-81839.rs +ui/suggestions/issue-82361.rs +ui/suggestions/issue-82566-1.rs +ui/suggestions/issue-82566-2.rs +ui/suggestions/issue-83892.rs +ui/suggestions/issue-83943.rs +ui/suggestions/issue-84592.rs +ui/suggestions/issue-84700.rs +ui/suggestions/issue-84973-2.rs +ui/suggestions/issue-84973-blacklist.rs +ui/suggestions/issue-84973-negative.rs +ui/suggestions/issue-84973.rs +ui/suggestions/issue-85347.rs +ui/suggestions/issue-85943-no-suggest-unsized-indirection-in-where-clause.rs +ui/suggestions/issue-85945-check-where-clause-before-suggesting-unsized.rs +ui/suggestions/issue-86100-tuple-paren-comma.rs +ui/suggestions/issue-86667.rs +ui/suggestions/issue-88696.rs +ui/suggestions/issue-88730.rs +ui/suggestions/issue-89064.rs +ui/suggestions/issue-89333.rs +ui/suggestions/issue-89640.rs +ui/suggestions/issue-90213-expected-boxfuture-self-ice.rs +ui/suggestions/issue-90974.rs +ui/suggestions/issue-94171.rs +ui/suggestions/issue-96223.rs +ui/suggestions/issue-96555.rs +ui/suggestions/issue-97677.rs +ui/suggestions/issue-97704.rs +ui/suggestions/issue-97760.rs +ui/suggestions/issue-98500.rs +ui/suggestions/issue-98562.rs +ui/suggestions/issue-99080.rs +ui/suggestions/issue-99240-2.rs +ui/suggestions/issue-99240.rs +ui/suggestions/issue-99597.rs +ui/suggestions/lifetimes/issue-105544.rs +ui/symbol-names/issue-53912.rs +ui/symbol-names/issue-60925.rs +ui/symbol-names/issue-75326.rs +ui/symbol-names/issue-76365.rs +ui/test-attrs/custom-test-frameworks/issue-107454.rs +ui/test-attrs/issue-109816.rs +ui/test-attrs/issue-12997-1.rs +ui/test-attrs/issue-12997-2.rs +ui/test-attrs/issue-16597-empty.rs +ui/test-attrs/issue-16597.rs +ui/test-attrs/issue-20823.rs +ui/test-attrs/issue-34932.rs +ui/test-attrs/issue-36768.rs +ui/test-attrs/issue-52557.rs +ui/test-attrs/issue-53675-a-test-called-panic.rs +ui/threads-sendsync/issue-24313.rs +ui/threads-sendsync/issue-29488.rs +ui/threads-sendsync/issue-43733-2.rs +ui/threads-sendsync/issue-43733.rs +ui/threads-sendsync/issue-4446.rs +ui/threads-sendsync/issue-4448.rs +ui/threads-sendsync/issue-8827.rs +ui/threads-sendsync/issue-9396.rs +ui/trait-bounds/issue-119530-sugg-from-fn.rs +ui/trait-bounds/issue-75961.rs +ui/trait-bounds/issue-82038.rs +ui/trait-bounds/issue-93008.rs +ui/trait-bounds/issue-94680.rs +ui/trait-bounds/issue-94999.rs +ui/trait-bounds/issue-95640.rs +ui/traits/alias/issue-107747-do-not-assemble-supertraits.rs +ui/traits/alias/issue-108072-unmet-trait-alias-bound.rs +ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs +ui/traits/alias/issue-60021-assoc-method-resolve.rs +ui/traits/alias/issue-60755.rs +ui/traits/alias/issue-72415-assoc-const-resolve.rs +ui/traits/alias/issue-75983.rs +ui/traits/alias/issue-83613.rs +ui/traits/associated_type_bound/issue-51446.rs +ui/traits/auxiliary/issue_89119_intercrate_caching.rs +ui/traits/issue-103563.rs +ui/traits/issue-104322.rs +ui/traits/issue-105231.rs +ui/traits/issue-106072.rs +ui/traits/issue-117794.rs +ui/traits/issue-15155.rs +ui/traits/issue-18400.rs +ui/traits/issue-18412.rs +ui/traits/issue-20692.rs +ui/traits/issue-21837.rs +ui/traits/issue-22019.rs +ui/traits/issue-22110.rs +ui/traits/issue-22384.rs +ui/traits/issue-22655.rs +ui/traits/issue-23003-overflow.rs +ui/traits/issue-23003.rs +ui/traits/issue-23825.rs +ui/traits/issue-24010.rs +ui/traits/issue-2611-3.rs +ui/traits/issue-26339.rs +ui/traits/issue-28576.rs +ui/traits/issue-32963.rs +ui/traits/issue-33096.rs +ui/traits/issue-33140-hack-boundaries.rs +ui/traits/issue-33140.rs +ui/traits/issue-33187.rs +ui/traits/issue-35869.rs +ui/traits/issue-3683.rs +ui/traits/issue-38033.rs +ui/traits/issue-38404.rs +ui/traits/issue-38604.rs +ui/traits/issue-3973.rs +ui/traits/issue-3979-generics.rs +ui/traits/issue-40085.rs +ui/traits/issue-4107.rs +ui/traits/issue-43132.rs +ui/traits/issue-43784-supertrait.rs +ui/traits/issue-5008-borrowed-traitobject-method-call.rs +ui/traits/issue-50480.rs +ui/traits/issue-52893.rs +ui/traits/issue-56202.rs +ui/traits/issue-56488.rs +ui/traits/issue-58344.rs +ui/traits/issue-59029-1.rs +ui/traits/issue-59029-2.rs +ui/traits/issue-6128.rs +ui/traits/issue-6334.rs +ui/traits/issue-65284-suggest-generic-trait-bound.rs +ui/traits/issue-65673.rs +ui/traits/issue-66768.rs +ui/traits/issue-68295.rs +ui/traits/issue-7013.rs +ui/traits/issue-70944.rs +ui/traits/issue-71036.rs +ui/traits/issue-71136.rs +ui/traits/issue-72410.rs +ui/traits/issue-72455.rs +ui/traits/issue-75627.rs +ui/traits/issue-77982.rs +ui/traits/issue-78372.rs +ui/traits/issue-78632.rs +ui/traits/issue-79458.rs +ui/traits/issue-8153.rs +ui/traits/issue-82830.rs +ui/traits/issue-83538-tainted-cache-after-cycle.rs +ui/traits/issue-84399-bad-fresh-caching.rs +ui/traits/issue-85360-eval-obligation-ice.rs +ui/traits/issue-85735.rs +ui/traits/issue-87558.rs +ui/traits/issue-89119.rs +ui/traits/issue-90195-2.rs +ui/traits/issue-90195.rs +ui/traits/issue-90662-projection-caching.rs +ui/traits/issue-91594.rs +ui/traits/issue-91949-hangs-on-recursion.rs +ui/traits/issue-92292.rs +ui/traits/issue-9394-inherited-calls.rs +ui/traits/issue-95311.rs +ui/traits/issue-95898.rs +ui/traits/issue-96664.rs +ui/traits/issue-96665.rs +ui/traits/issue-97576.rs +ui/traits/issue-97695-double-trivial-bound.rs +ui/traits/issue-99875.rs +ui/traits/next-solver/coherence/issue-102048.rs +ui/traits/next-solver/issue-118950-root-region.rs +ui/traits/object/issue-33140-traitobject-crate.rs +ui/traits/object/issue-44454-1.rs +ui/traits/object/issue-44454-2.rs +ui/traits/object/issue-44454-3.rs +ui/traits/suggest-dereferences/issue-39029.rs +ui/traits/suggest-dereferences/issue-62530.rs +ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs +ui/traits/trait-upcasting/issue-11515.rs +ui/traits/vtable/issue-91807.rs +ui/traits/vtable/issue-97381.rs +ui/transmutability/arrays/issue-103783-array-length.rs +ui/transmutability/issue-101739-1.rs +ui/transmutability/issue-101739-2.rs +ui/transmutability/issue-110467.rs +ui/transmutability/issue-110892.rs +ui/trivial-bounds/issue-73021-impossible-inline.rs +ui/try-block/issue-45124.rs +ui/try-trait/issue-32709.rs +ui/type-alias-enum-variants/issue-57866.rs +ui/type-alias-enum-variants/issue-61801-path-pattern-can-infer.rs +ui/type-alias-enum-variants/issue-63151-dead-code-lint-fields-in-patterns.rs +ui/type-alias-impl-trait/issue-101750.rs +ui/type-alias-impl-trait/issue-104817.rs +ui/type-alias-impl-trait/issue-109054.rs +ui/type-alias-impl-trait/issue-52843-closure-constrain.rs +ui/type-alias-impl-trait/issue-52843.rs +ui/type-alias-impl-trait/issue-53092-2.rs +ui/type-alias-impl-trait/issue-53092.rs +ui/type-alias-impl-trait/issue-53096.rs +ui/type-alias-impl-trait/issue-53598.rs +ui/type-alias-impl-trait/issue-53678-coroutine-and-const-fn.rs +ui/type-alias-impl-trait/issue-55099-lifetime-inference.rs +ui/type-alias-impl-trait/issue-57188-associate-impl-capture.rs +ui/type-alias-impl-trait/issue-57611-trait-alias.rs +ui/type-alias-impl-trait/issue-57700.rs +ui/type-alias-impl-trait/issue-57807-associated-type.rs +ui/type-alias-impl-trait/issue-57961.rs +ui/type-alias-impl-trait/issue-58662-coroutine-with-lifetime.rs +ui/type-alias-impl-trait/issue-58662-simplified.rs +ui/type-alias-impl-trait/issue-58887.rs +ui/type-alias-impl-trait/issue-58951-2.rs +ui/type-alias-impl-trait/issue-58951.rs +ui/type-alias-impl-trait/issue-60371.rs +ui/type-alias-impl-trait/issue-60407.rs +ui/type-alias-impl-trait/issue-60564-working.rs +ui/type-alias-impl-trait/issue-60564.rs +ui/type-alias-impl-trait/issue-60662.rs +ui/type-alias-impl-trait/issue-62000-associate-impl-trait-lifetimes.rs +ui/type-alias-impl-trait/issue-63263-closure-return.rs +ui/type-alias-impl-trait/issue-63279.rs +ui/type-alias-impl-trait/issue-63355.rs +ui/type-alias-impl-trait/issue-63677-type-alias-coherence.rs +ui/type-alias-impl-trait/issue-65384.rs +ui/type-alias-impl-trait/issue-65679-inst-opaque-ty-from-val-twice.rs +ui/type-alias-impl-trait/issue-65918.rs +ui/type-alias-impl-trait/issue-66580-closure-coherence.rs +ui/type-alias-impl-trait/issue-67844-nested-opaque.rs +ui/type-alias-impl-trait/issue-68368-non-defining-use-2.rs +ui/type-alias-impl-trait/issue-68368-non-defining-use.rs +ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs +ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-ok.rs +ui/type-alias-impl-trait/issue-69323.rs +ui/type-alias-impl-trait/issue-70121.rs +ui/type-alias-impl-trait/issue-72793.rs +ui/type-alias-impl-trait/issue-74244.rs +ui/type-alias-impl-trait/issue-74280.rs +ui/type-alias-impl-trait/issue-74761-2.rs +ui/type-alias-impl-trait/issue-74761.rs +ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs +ui/type-alias-impl-trait/issue-77179.rs +ui/type-alias-impl-trait/issue-78450.rs +ui/type-alias-impl-trait/issue-84660-trait-impl-for-tait.rs +ui/type-alias-impl-trait/issue-84660-unsoundness.rs +ui/type-alias-impl-trait/issue-87455-static-lifetime-ice.rs +ui/type-alias-impl-trait/issue-89686.rs +ui/type-alias-impl-trait/issue-89952.rs +ui/type-alias-impl-trait/issue-90400-1.rs +ui/type-alias-impl-trait/issue-90400-2.rs +ui/type-alias-impl-trait/issue-93411.rs +ui/type-alias-impl-trait/issue-94429.rs +ui/type-alias-impl-trait/issue-96572-unconstrained-mismatch.rs +ui/type-alias-impl-trait/issue-96572-unconstrained.rs +ui/type-alias-impl-trait/issue-98604.rs +ui/type-alias-impl-trait/issue-98608.rs +ui/type-alias/issue-14933.rs +ui/type-alias/issue-37515.rs +ui/type-alias/issue-62263-self-in-atb.rs +ui/type-alias/issue-62305-self-assoc-ty.rs +ui/type-alias/issue-62364-self-ty-arg.rs +ui/type-inference/issue-113283-alllocator-trait-eq.rs +ui/type-inference/issue-30225.rs +ui/type/ascription/issue-34255-1.rs +ui/type/ascription/issue-47666.rs +ui/type/ascription/issue-54516.rs +ui/type/ascription/issue-60933.rs +ui/type/issue-100584.rs +ui/type/issue-101866.rs +ui/type/issue-102598.rs +ui/type/issue-103271.rs +ui/type/issue-58355.rs +ui/type/issue-67690-type-alias-bound-diagnostic-crash.rs +ui/type/issue-91268.rs +ui/type/issue-94187-verbose-type-name.rs +ui/type/type-check/issue-116967-cannot-coerce-returned-result.rs +ui/type/type-check/issue-22897.rs +ui/type/type-check/issue-40294.rs +ui/type/type-check/issue-41314.rs +ui/type/type-check/issue-67273-assignment-match-prior-arm-bool-expected-unit.rs +ui/type/type-check/issue-88577-check-fn-with-more-than-65535-arguments.rs +ui/typeck/auxiliary/issue-29181.rs +ui/typeck/auxiliary/issue-36708.rs +ui/typeck/auxiliary/issue-81943-lib.rs +ui/typeck/issue-100164.rs +ui/typeck/issue-100246.rs +ui/typeck/issue-100285.rs +ui/typeck/issue-103899.rs +ui/typeck/issue-10401.rs +ui/typeck/issue-104510-ice.rs +ui/typeck/issue-104513-ice.rs +ui/typeck/issue-104582.rs +ui/typeck/issue-105946.rs +ui/typeck/issue-106929.rs +ui/typeck/issue-107087.rs +ui/typeck/issue-107775.rs +ui/typeck/issue-10969.rs +ui/typeck/issue-110017-format-into-help-deletes-macro.rs +ui/typeck/issue-110052.rs +ui/typeck/issue-112007-leaked-writeln-macro-internals.rs +ui/typeck/issue-112252-ptr-arithmetics-help.rs +ui/typeck/issue-112385-while-assign-lhs-place-expr-ice.rs +ui/typeck/issue-114423-ice-regression-in-suggestion.rs +ui/typeck/issue-114529-illegal-break-with-value.rs +ui/typeck/issue-116473-ice-wrong-span-variant-args.rs +ui/typeck/issue-116864.rs +ui/typeck/issue-120856.rs +ui/typeck/issue-13853-2.rs +ui/typeck/issue-13853-5.rs +ui/typeck/issue-13853.rs +ui/typeck/issue-16338.rs +ui/typeck/issue-1871.rs +ui/typeck/issue-18937-1.rs +ui/typeck/issue-18937.rs +ui/typeck/issue-2063-resource.rs +ui/typeck/issue-2063.rs +ui/typeck/issue-22375.rs +ui/typeck/issue-29124.rs +ui/typeck/issue-29181.rs +ui/typeck/issue-31173.rs +ui/typeck/issue-33575.rs +ui/typeck/issue-36708.rs +ui/typeck/issue-43189.rs +ui/typeck/issue-46112.rs +ui/typeck/issue-50687-ice-on-borrow.rs +ui/typeck/issue-52082-type-param-shadows-existing-type.rs +ui/typeck/issue-53712.rs +ui/typeck/issue-55810-must-typeck-match-pats-before-guards.rs +ui/typeck/issue-57404.rs +ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.rs +ui/typeck/issue-61711-once-caused-rustc-inf-loop.rs +ui/typeck/issue-65611.rs +ui/typeck/issue-67971.rs +ui/typeck/issue-68590-reborrow-through-derefmut.rs +ui/typeck/issue-69378-ice-on-invalid-type-node-after-recovery.rs +ui/typeck/issue-72225-call-fnmut-through-derefmut.rs +ui/typeck/issue-73592-borrow_mut-through-deref.rs +ui/typeck/issue-74086.rs +ui/typeck/issue-74933.rs +ui/typeck/issue-75883.rs +ui/typeck/issue-75889.rs +ui/typeck/issue-7813.rs +ui/typeck/issue-79040.rs +ui/typeck/issue-80207-unsized-return.rs +ui/typeck/issue-80779.rs +ui/typeck/issue-81293.rs +ui/typeck/issue-81885.rs +ui/typeck/issue-81943.rs +ui/typeck/issue-82772.rs +ui/typeck/issue-83621-placeholder-static-in-extern.rs +ui/typeck/issue-83693.rs +ui/typeck/issue-84160.rs +ui/typeck/issue-84768.rs +ui/typeck/issue-84831.rs +ui/typeck/issue-86721-return-expr-ice.rs +ui/typeck/issue-87771-ice-assign-assign-to-bool.rs +ui/typeck/issue-87872-missing-inaccessible-field-literal.rs +ui/typeck/issue-87872-missing-inaccessible-field-pattern.rs +ui/typeck/issue-88609.rs +ui/typeck/issue-88643.rs +ui/typeck/issue-88803-call-expr-method.rs +ui/typeck/issue-88844.rs +ui/typeck/issue-89044-wrapped-expr-method.rs +ui/typeck/issue-89275.rs +ui/typeck/issue-89806.rs +ui/typeck/issue-89856.rs +ui/typeck/issue-89935.rs +ui/typeck/issue-90027-async-fn-return-suggestion.rs +ui/typeck/issue-90101.rs +ui/typeck/issue-90164.rs +ui/typeck/issue-90319.rs +ui/typeck/issue-90483-inaccessible-field-adjustment.rs +ui/typeck/issue-90804-incorrect-reference-suggestion.rs +ui/typeck/issue-91210-ptr-method.rs +ui/typeck/issue-91267.rs +ui/typeck/issue-91328.rs +ui/typeck/issue-91334.rs +ui/typeck/issue-91450-inner-ty-error.rs +ui/typeck/issue-91633.rs +ui/typeck/issue-92481.rs +ui/typeck/issue-93486.rs +ui/typeck/issue-96530.rs +ui/typeck/issue-96738.rs +ui/typeck/issue-98260.rs +ui/typeck/issue-98982.rs +ui/typeof/issue-100183.rs +ui/typeof/issue-29184.rs +ui/typeof/issue-42060.rs +ui/unboxed-closures/issue-18652.rs +ui/unboxed-closures/issue-18661.rs +ui/unboxed-closures/issue-30906.rs +ui/unboxed-closures/issue-53448.rs +ui/underscore-imports/issue-110164.rs +ui/uniform-paths/auxiliary/issue-53691.rs +ui/uniform-paths/issue-53691.rs +ui/uninhabited/issue-107505.rs +ui/union/issue-41073.rs +ui/union/issue-81199.rs +ui/union/issue-99375.rs +ui/unsafe/auxiliary/issue-106126.rs +ui/unsafe/issue-106126-good-path-bug.rs +ui/unsafe/issue-115348-false-positive-warning-of-unnecessary-unsafe.rs +ui/unsafe/issue-3080.rs +ui/unsafe/issue-45087-unreachable-unsafe.rs +ui/unsafe/issue-45107-unnecessary-unsafe-in-closure.rs +ui/unsafe/issue-47412.rs +ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs +ui/unsafe/issue-87414-query-cycle.rs +ui/unsized-locals/issue-30276-feature-flagged.rs +ui/unsized-locals/issue-30276.rs +ui/unsized-locals/issue-50940-with-feature.rs +ui/unsized-locals/issue-50940.rs +ui/unsized-locals/issue-67981.rs +ui/unsized/issue-115203.rs +ui/unsized/issue-115809.rs +ui/unsized/issue-23649-1.rs +ui/unsized/issue-23649-2.rs +ui/unsized/issue-23649-3.rs +ui/unsized/issue-30355.rs +ui/unsized/issue-40231-1.rs +ui/unsized/issue-40231-2.rs +ui/unsized/issue-71659.rs +ui/unsized/issue-75707.rs +ui/unsized/issue-75899-but-gats.rs +ui/unsized/issue-75899.rs +ui/unsized/issue-91801.rs +ui/unsized/issue-91803.rs +ui/unsized/issue-97732.rs +ui/use/issue-18986.rs +ui/use/issue-60976-extern-use-primitive-type.rs +ui/wf/issue-103573.rs +ui/wf/issue-110157.rs +ui/wf/issue-48638.rs +ui/wf/issue-87495.rs +ui/wf/issue-95665.rs +ui/wf/issue-96810.rs +ui/where-clauses/issue-50825-1.rs +ui/where-clauses/issue-50825.rs diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 454811c5fbb..78de8c0537d 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,8 +17,8 @@ use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: usize = 1733; -const ROOT_ENTRY_LIMIT: usize = 860; +const ISSUES_ENTRY_LIMIT: usize = 1722; +const ROOT_ENTRY_LIMIT: usize = 859; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files @@ -49,6 +49,9 @@ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/shell-argfiles/shell-argfiles-badquotes.args", // passing args via a file "tests/ui/shell-argfiles/shell-argfiles-via-argfile-shell.args", // passing args via a file "tests/ui/shell-argfiles/shell-argfiles-via-argfile.args", // passing args via a file + "tests/ui/std/windows-bat-args1.bat", // tests escaping arguments through batch files + "tests/ui/std/windows-bat-args2.bat", // tests escaping arguments through batch files + "tests/ui/std/windows-bat-args3.bat", // tests escaping arguments through batch files ]; fn check_entries(tests_path: &Path, bad: &mut bool) { @@ -100,15 +103,32 @@ fn check_entries(tests_path: &Path, bad: &mut bool) { } pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { + let issues_txt_header = r#"============================================================ + ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️ +============================================================ +"#; + let path = &root_path.join("tests"); check_entries(&path, bad); // the list of files in ui tests that are allowed to start with `issue-XXXX` // BTreeSet because we would like a stable ordering so --bless works - let issues_list = - include!("issues.txt").map(|path| path.replace("/", std::path::MAIN_SEPARATOR_STR)); - let issues: Vec<String> = Vec::from(issues_list.clone()); - let is_sorted = issues.windows(2).all(|w| w[0] < w[1]); + let mut prev_line = ""; + let mut is_sorted = true; + let allowed_issue_names: BTreeSet<_> = include_str!("issues.txt") + .strip_prefix(issues_txt_header) + .unwrap() + .lines() + .map(|line| { + if prev_line > line { + is_sorted = false; + } + + prev_line = line; + line + }) + .collect(); + if !is_sorted && !bless { tidy_error!( bad, @@ -116,9 +136,8 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { please only update it with command `x test tidy --bless`" ); } - let allowed_issue_names = BTreeSet::from(issues_list); - let mut remaining_issue_names: BTreeSet<String> = allowed_issue_names.clone(); + let mut remaining_issue_names: BTreeSet<&str> = allowed_issue_names.clone(); let (ui, ui_fulldeps) = (path.join("ui"), path.join("ui-fulldeps")); let paths = [ui.as_path(), ui_fulldeps.as_path()]; @@ -170,8 +189,14 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { if let Some(test_name) = ISSUE_NAME_REGEX.captures(testname) { // these paths are always relative to the passed `path` and always UTF8 - let stripped_path = file_path.strip_prefix(path).unwrap().to_str().unwrap(); - if !remaining_issue_names.remove(stripped_path) { + let stripped_path = file_path + .strip_prefix(path) + .unwrap() + .to_str() + .unwrap() + .replace(std::path::MAIN_SEPARATOR_STR, "/"); + + if !remaining_issue_names.remove(stripped_path.as_str()) { tidy_error!( bad, "file `tests/{stripped_path}` must begin with a descriptive name, consider `{{reason}}-issue-{issue_n}.rs`", @@ -186,15 +211,7 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { // if there are any file names remaining, they were moved on the fs. // our data must remain up to date, so it must be removed from issues.txt // do this automatically on bless, otherwise issue a tidy error - if bless && !remaining_issue_names.is_empty() { - let issues_txt_header = r#" -/* -============================================================ - ⚠️⚠️⚠️NOTHING SHOULD EVER BE ADDED TO THIS LIST⚠️⚠️⚠️ -============================================================ -*/ -[ -"#; + if bless && (!remaining_issue_names.is_empty() || !is_sorted) { let tidy_src = root_path.join("src/tools/tidy/src"); // instead of overwriting the file, recreate it and use an "atomic rename" // so we don't bork things on panic or a contributor using Ctrl+C @@ -202,13 +219,9 @@ pub fn check(root_path: &Path, bless: bool, bad: &mut bool) { let mut blessed_issues_txt = fs::File::create(&blessed_issues_path).unwrap(); blessed_issues_txt.write(issues_txt_header.as_bytes()).unwrap(); // If we changed paths to use the OS separator, reassert Unix chauvinism for blessing. - for filename in allowed_issue_names - .difference(&remaining_issue_names) - .map(|s| s.replace(std::path::MAIN_SEPARATOR_STR, "/")) - { - write!(blessed_issues_txt, "\"{filename}\",\n").unwrap(); + for filename in allowed_issue_names.difference(&remaining_issue_names) { + writeln!(blessed_issues_txt, "{filename}").unwrap(); } - write!(blessed_issues_txt, "]\n").unwrap(); let old_issues_path = tidy_src.join("issues.txt"); fs::rename(blessed_issues_path, old_issues_path).unwrap(); } else { diff --git a/tests/codegen/enum/enum-early-otherwise-branch.rs b/tests/codegen/enum/enum-early-otherwise-branch.rs new file mode 100644 index 00000000000..6c7548912da --- /dev/null +++ b/tests/codegen/enum/enum-early-otherwise-branch.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18 + +#![crate_type = "lib"] + +pub enum Enum { + A(u32), + B(u32), + C(u32), +} + +#[no_mangle] +pub fn foo(lhs: &Enum, rhs: &Enum) -> bool { + // CHECK-LABEL: define{{.*}}i1 @foo( + // CHECK-NOT: switch + // CHECK-NOT: br + // CHECK: [[SELECT:%.*]] = select + // CHECK-NEXT: ret i1 [[SELECT]] + // CHECK-NEXT: } + match (lhs, rhs) { + (Enum::A(lhs), Enum::A(rhs)) => lhs == rhs, + (Enum::B(lhs), Enum::B(rhs)) => lhs == rhs, + (Enum::C(lhs), Enum::C(rhs)) => lhs == rhs, + _ => false, + } +} diff --git a/tests/codegen/issues/issue-122805.rs b/tests/codegen/issues/issue-122805.rs new file mode 100644 index 00000000000..6a5be39238f --- /dev/null +++ b/tests/codegen/issues/issue-122805.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -O +//@ min-llvm-version: 18.1.3 + +#![crate_type = "lib"] +#![no_std] + +// The code is from https://github.com/rust-lang/rust/issues/122805. +// Ensure we do not generate the shufflevector instruction +// to avoid complicating the code. +// CHECK-LABEL: define{{.*}}void @convert( +// CHECK-NOT: shufflevector +// CHECK: insertelement <8 x i16> +// CHECK-NEXT: insertelement <8 x i16> +// CHECK-NEXT: insertelement <8 x i16> +// CHECK-NEXT: insertelement <8 x i16> +// CHECK-NEXT: insertelement <8 x i16> +// CHECK-NEXT: insertelement <8 x i16> +// CHECK-NEXT: insertelement <8 x i16> +// CHECK-NEXT: insertelement <8 x i16> +// CHECK-NEXT: store <8 x i16> +// CHECK-NEXT: ret void +#[no_mangle] +#[cfg(target_endian = "little")] +pub fn convert(value: [u16; 8]) -> [u8; 16] { + let addr16 = [ + value[0].to_be(), + value[1].to_be(), + value[2].to_be(), + value[3].to_be(), + value[4].to_be(), + value[5].to_be(), + value[6].to_be(), + value[7].to_be(), + ]; + unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) } +} diff --git a/tests/codegen/match-optimized.rs b/tests/codegen/match-optimized.rs index 09907edf8f2..5cecafb9f29 100644 --- a/tests/codegen/match-optimized.rs +++ b/tests/codegen/match-optimized.rs @@ -26,12 +26,12 @@ pub fn exhaustive_match(e: E) -> u8 { // CHECK-NEXT: store i8 1, ptr %_0, align 1 // CHECK-NEXT: br label %[[EXIT]] // CHECK: [[C]]: -// CHECK-NEXT: store i8 2, ptr %_0, align 1 +// CHECK-NEXT: store i8 3, ptr %_0, align 1 // CHECK-NEXT: br label %[[EXIT]] match e { E::A => 0, E::B => 1, - E::C => 2, + E::C => 3, } } diff --git a/tests/codegen/pattern_type_symbols.rs b/tests/codegen/pattern_type_symbols.rs new file mode 100644 index 00000000000..dfe83443348 --- /dev/null +++ b/tests/codegen/pattern_type_symbols.rs @@ -0,0 +1,23 @@ +//! Check that symbol names with pattern types in them are +//! different from the same symbol with the base type + +//@ compile-flags: -Csymbol-mangling-version=v0 -Copt-level=0 --crate-type=lib + +#![feature(pattern_types)] +#![feature(core_pattern_types)] +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +type NanoU32 = crate::pattern_type!(u32 is 0..=999_999_999); + +fn foo<T>() {} + +pub fn bar() { + // CHECK: call pattern_type_symbols::foo::<u32> + // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3foomEB2_ + foo::<u32>(); + // CHECK: call pattern_type_symbols::foo::<(u32, [(); 0], [(); 999999999], [(); true])> + // CHECK: call void @_RINvCs3QvG2ESzx2Q_20pattern_type_symbols3fooTmAum0_Aum3b9ac9ff_Aub1_EEB2_ + foo::<NanoU32>(); +} diff --git a/tests/codegen/powerpc64le-struct-align-128.rs b/tests/codegen/powerpc64le-struct-align-128.rs new file mode 100644 index 00000000000..0096c6d3138 --- /dev/null +++ b/tests/codegen/powerpc64le-struct-align-128.rs @@ -0,0 +1,93 @@ +// Test that structs aligned to 128 bits are passed with the correct ABI on powerpc64le. +// This is similar to aarch64-struct-align-128.rs, but for ppc. + +//@ compile-flags: --target powerpc64le-unknown-linux-gnu +//@ needs-llvm-components: powerpc + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang="sized"] +trait Sized { } +#[lang="freeze"] +trait Freeze { } +#[lang="copy"] +trait Copy { } + +#[repr(C)] +pub struct Align8 { + pub a: u64, + pub b: u64, +} + +#[repr(transparent)] +pub struct Transparent8 { + a: Align8 +} + +#[repr(C)] +pub struct Wrapped8 { + a: Align8, +} + +extern "C" { + // CHECK: declare void @test_8([2 x i64], [2 x i64], [2 x i64]) + fn test_8(a: Align8, b: Transparent8, c: Wrapped8); +} + +#[repr(C)] +#[repr(align(16))] +pub struct Align16 { + pub a: u64, + pub b: u64, +} + +#[repr(transparent)] +pub struct Transparent16 { + a: Align16 +} + +#[repr(C)] +pub struct Wrapped16 { + pub a: Align16, +} + +extern "C" { + // It's important that this produces [1 x i128] rather than just i128! + // CHECK: declare void @test_16([1 x i128], [1 x i128], [1 x i128]) + fn test_16(a: Align16, b: Transparent16, c: Wrapped16); +} + +#[repr(C)] +#[repr(align(32))] +pub struct Align32 { + pub a: u64, + pub b: u64, + pub c: u64, +} + +#[repr(transparent)] +pub struct Transparent32 { + a: Align32 +} + +#[repr(C)] +pub struct Wrapped32 { + pub a: Align32, +} + +extern "C" { + // CHECK: declare void @test_32([2 x i128], [2 x i128], [2 x i128]) + fn test_32(a: Align32, b: Transparent32, c: Wrapped32); +} + +pub unsafe fn main( + a1: Align8, a2: Transparent8, a3: Wrapped8, + b1: Align16, b2: Transparent16, b3: Wrapped16, + c1: Align32, c2: Transparent32, c3: Wrapped32, +) { + test_8(a1, a2, a3); + test_16(b1, b2, b3); + test_32(c1, c2, c3); +} diff --git a/tests/codegen/riscv-target-abi.rs b/tests/codegen/riscv-target-abi.rs new file mode 100644 index 00000000000..5d545af9c76 --- /dev/null +++ b/tests/codegen/riscv-target-abi.rs @@ -0,0 +1,20 @@ +//@ revisions:riscv64gc riscv32gc riscv32imac + +//@[riscv64gc] compile-flags: --target=riscv64gc-unknown-linux-gnu +//@[riscv64gc] needs-llvm-components: riscv +// riscv64gc: !{i32 1, !"target-abi", !"lp64d"} + +//@[riscv32gc] compile-flags: --target=riscv32gc-unknown-linux-musl +//@[riscv32gc] needs-llvm-components: riscv +// riscv32gc: !{i32 1, !"target-abi", !"ilp32d"} + +//@[riscv32imac] compile-flags: --target=riscv32imac-unknown-none-elf +//@[riscv32imac] needs-llvm-components: riscv +// riscv32imac-NOT: !"target-abi" + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs index ab3d339989b..c5dadf70de9 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-function-types.rs @@ -34,12 +34,12 @@ pub fn foo12(_: &dyn FnOnce(i32) -> i32, _: &dyn FnOnce(i32) -> i32, _: &dyn FnO // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} // CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEEE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEEE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEEE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu6regionEES3_S3_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs index cc7178e41c7..6d9fe7040f7 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-trait-types.rs @@ -132,7 +132,7 @@ pub fn foo27(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>, _: &dyn Trait // CHECK: define{{.*}}5foo27{{.*}}!type ![[TYPE27:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: ![[TYPE13]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEEE"} -// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu5paramEu6regionEEE"} +// CHECK: ![[TYPE16]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEEE"} // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} // CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} // CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} @@ -148,14 +148,14 @@ pub fn foo27(_: &dyn Trait5<Type5, 32>, _: &dyn Trait5<Type5, 32>, _: &dyn Trait // CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker{{(4Send|4Sync)}}u6regionEES4_S4_E"} // CHECK: ![[TYPE14]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_E"} // CHECK: ![[TYPE15]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait1u6regionEES2_S2_E"} -// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu5paramEu6regionEEE"} -// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu5paramEu6regionEES3_E"} -// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu5paramEu6regionEES3_S3_E"} -// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu5paramEu6regionEEE"} -// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu5paramEu6regionEES4_E"} -// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu5paramEu6regionEES4_S4_E"} -// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu5paramLu5usizeEEu6regionEEE"} -// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu5paramLu5usizeEEu6regionEES5_E"} -// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu5paramLu5usizeEEu6regionEES5_S5_E"} +// CHECK: ![[TYPE17]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_E"} +// CHECK: ![[TYPE18]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait2Iu3i32Eu6regionEES3_S3_E"} +// CHECK: ![[TYPE19]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEEE"} +// CHECK: ![[TYPE20]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_E"} +// CHECK: ![[TYPE21]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait3Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type3Eu6regionEES3_S3_E"} +// CHECK: ![[TYPE22]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EEE"} +// CHECK: ![[TYPE23]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_E"} +// CHECK: ![[TYPE24]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait4Iu6regionu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type4Eu{{[0-9]+}}NtNtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait46OutputIS_S0_Eu3refIu3i32ES_EES6_S6_E"} +// CHECK: ![[TYPE25]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEEE"} +// CHECK: ![[TYPE26]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_E"} +// CHECK: ![[TYPE27]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}6Trait5Iu{{[0-9]+}}NtC{{[[:print:]]+}}_{{[[:print:]]+}}5Type5Lu5usize32EEu6regionEES5_S5_E"} diff --git a/tests/codegen/slice-indexing.rs b/tests/codegen/slice-indexing.rs index ecce9201071..3d284148db2 100644 --- a/tests/codegen/slice-indexing.rs +++ b/tests/codegen/slice-indexing.rs @@ -32,3 +32,31 @@ pub unsafe fn get_unchecked_mut_by_range(x: &mut [i32], r: Range<usize>) -> &mut // CHECK: sub nuw i64 x.get_unchecked_mut(r) } + +// CHECK-LABEL: @str_index_by_range( +#[no_mangle] +pub fn str_index_by_range(x: &str, r: Range<usize>) -> &str { + // CHECK: sub nuw i64 + &x[r] +} + +// CHECK-LABEL: @str_get_unchecked_by_range( +#[no_mangle] +pub unsafe fn str_get_unchecked_by_range(x: &str, r: Range<usize>) -> &str { + // CHECK: sub nuw i64 + x.get_unchecked(r) +} + +// CHECK-LABEL: @str_index_mut_by_range( +#[no_mangle] +pub fn str_index_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str { + // CHECK: sub nuw i64 + &mut x[r] +} + +// CHECK-LABEL: @str_get_unchecked_mut_by_range( +#[no_mangle] +pub unsafe fn str_get_unchecked_mut_by_range(x: &mut str, r: Range<usize>) -> &mut str { + // CHECK: sub nuw i64 + x.get_unchecked_mut(r) +} diff --git a/tests/codegen/step_by-overflow-checks.rs b/tests/codegen/step_by-overflow-checks.rs new file mode 100644 index 00000000000..43e8514a8b7 --- /dev/null +++ b/tests/codegen/step_by-overflow-checks.rs @@ -0,0 +1,26 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +use std::iter::StepBy; +use std::slice::Iter; + +// The constructor for `StepBy` ensures we can never end up needing to do zero +// checks on denominators, so check that the code isn't emitting panic paths. + +// CHECK-LABEL: @step_by_len_std +#[no_mangle] +pub fn step_by_len_std(x: &StepBy<Iter<i32>>) -> usize { + // CHECK-NOT: div_by_zero + // CHECK: udiv + // CHECK-NOT: div_by_zero + x.len() +} + +// CHECK-LABEL: @step_by_len_naive +#[no_mangle] +pub fn step_by_len_naive(x: Iter<i32>, step_minus_one: usize) -> usize { + // CHECK: udiv + // CHECK: call{{.+}}div_by_zero + x.len() / (step_minus_one + 1) +} diff --git a/tests/codegen/ub-checks.rs b/tests/codegen/ub-checks.rs new file mode 100644 index 00000000000..de48d74e652 --- /dev/null +++ b/tests/codegen/ub-checks.rs @@ -0,0 +1,28 @@ +// With -Zub-checks=yes (enabled by default by -Cdebug-assertions=yes) we will produce a runtime +// check that the index to slice::get_unchecked is in-bounds of the slice. That is tested for by +// tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs +// +// This test ensures that such a runtime check is *not* emitted when debug-assertions are enabled, +// but ub-checks are explicitly disabled. + +//@ revisions: DEBUG NOCHECKS +//@ [DEBUG] compile-flags: +//@ [NOCHECKS] compile-flags: -Zub-checks=no +//@ compile-flags: -O -Cdebug-assertions=yes + +#![crate_type = "lib"] + +use std::ops::Range; + +// CHECK-LABEL: @slice_get_unchecked( +#[no_mangle] +pub unsafe fn slice_get_unchecked(x: &[i32], i: usize) -> &i32 { + // CHECK: icmp ult + // NOCHECKS: tail call void @llvm.assume + // DEBUG: br i1 + // DEBUG: call core::panicking::panic_nounwind + // DEBUG: unreachable + // CHECK: getelementptr inbounds + // CHECK: ret ptr + x.get_unchecked(i) +} diff --git a/tests/codegen/vecdeque_pop_push.rs b/tests/codegen/vecdeque_pop_push.rs new file mode 100644 index 00000000000..040d5a279dc --- /dev/null +++ b/tests/codegen/vecdeque_pop_push.rs @@ -0,0 +1,67 @@ +//@ compile-flags: -O + +#![crate_type = "lib"] + +use std::collections::VecDeque; + +#[no_mangle] +// CHECK-LABEL: @noop_back( +pub fn noop_back(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @noop_front( +pub fn noop_front(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_front_to_back( +pub fn move_byte_front_to_back(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_front() { + v.push_back(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @move_byte_back_to_front( +pub fn move_byte_back_to_front(v: &mut VecDeque<u8>) { + // CHECK-NOT: grow + // CHECK: tail call void @llvm.assume + // CHECK-NOT: grow + // CHECK: ret + if let Some(x) = v.pop_back() { + v.push_front(x); + } +} + +#[no_mangle] +// CHECK-LABEL: @push_back_byte( +pub fn push_back_byte(v: &mut VecDeque<u8>) { + // CHECK: call {{.*}}grow + v.push_back(3); +} + +#[no_mangle] +// CHECK-LABEL: @push_front_byte( +pub fn push_front_byte(v: &mut VecDeque<u8>) { + // CHECK: call {{.*}}grow + v.push_front(3); +} diff --git a/tests/incremental/spike-neg1.rs b/tests/incremental/spike-neg1.rs index c5fe31862b4..356c61759f9 100644 --- a/tests/incremental/spike-neg1.rs +++ b/tests/incremental/spike-neg1.rs @@ -7,6 +7,7 @@ //@ revisions:rpass1 rpass2 //@ should-fail +//@ compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/tests/incremental/spike-neg2.rs b/tests/incremental/spike-neg2.rs index 140aa4684a7..9f69d7a757a 100644 --- a/tests/incremental/spike-neg2.rs +++ b/tests/incremental/spike-neg2.rs @@ -7,6 +7,7 @@ //@ revisions:rpass1 rpass2 //@ should-fail +//@ compile-flags: -Z query-dep-graph #![feature(rustc_attrs)] diff --git a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir index 76938c14e1e..cb72ad3d253 100644 --- a/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/address_of.address_of_reborrow.SimplifyCfg-initial.after.mir @@ -1,36 +1,36 @@ // MIR for `address_of_reborrow` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:8:5: 8:18, inferred_ty: *const [i32; 10] -| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:10:5: 10:25, inferred_ty: *const dyn std::marker::Send -| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] -| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] -| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send -| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] -| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:19:5: 19:18, inferred_ty: *const [i32; 10] -| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:21:5: 21:25, inferred_ty: *const dyn std::marker::Send -| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] -| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] -| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send -| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] -| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:29:5: 29:16, inferred_ty: *mut [i32; 10] -| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:31:5: 31:23, inferred_ty: *mut dyn std::marker::Send -| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] -| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] -| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send -| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] -| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 0: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:8:5: 8:18, inferred_ty: *const [i32; 10] +| 1: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:10:5: 10:25, inferred_ty: *const dyn std::marker::Send +| 2: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 3: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:14:12: 14:20, inferred_ty: *const [i32; 10] +| 4: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 5: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:15:12: 15:28, inferred_ty: *const [i32; 10] +| 6: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 7: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:16:12: 16:27, inferred_ty: *const dyn std::marker::Send +| 8: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 9: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:17:12: 17:24, inferred_ty: *const [i32] +| 10: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:19:5: 19:18, inferred_ty: *const [i32; 10] +| 11: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:21:5: 21:25, inferred_ty: *const dyn std::marker::Send +| 12: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 13: user_ty: Canonical { value: Ty(*const ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:24:12: 24:20, inferred_ty: *const [i32; 10] +| 14: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 15: user_ty: Canonical { value: Ty(*const [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:25:12: 25:28, inferred_ty: *const [i32; 10] +| 16: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 17: user_ty: Canonical { value: Ty(*const dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:26:12: 26:27, inferred_ty: *const dyn std::marker::Send +| 18: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 19: user_ty: Canonical { value: Ty(*const [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:27:12: 27:24, inferred_ty: *const [i32] +| 20: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:29:5: 29:16, inferred_ty: *mut [i32; 10] +| 21: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:31:5: 31:23, inferred_ty: *mut dyn std::marker::Send +| 22: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 23: user_ty: Canonical { value: Ty(*mut ^0), max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:34:12: 34:18, inferred_ty: *mut [i32; 10] +| 24: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 25: user_ty: Canonical { value: Ty(*mut [i32; 10]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:35:12: 35:26, inferred_ty: *mut [i32; 10] +| 26: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 27: user_ty: Canonical { value: Ty(*mut dyn std::marker::Send), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/address_of.rs:36:12: 36:25, inferred_ty: *mut dyn std::marker::Send +| 28: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] +| 29: user_ty: Canonical { value: Ty(*mut [i32]), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/address_of.rs:37:12: 37:22, inferred_ty: *mut [i32] | fn address_of_reborrow() -> () { let mut _0: (); diff --git a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 5df6633880e..5c0d1e9b93f 100644 --- a/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/tests/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after SimplifyCfg-initial | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> -| 1: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> +| 0: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> +| 1: user_ty: Canonical { value: Ty(std::option::Option<std::boxed::Box<u32>>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/basic_assignment.rs:38:17: 38:33, inferred_ty: std::option::Option<std::boxed::Box<u32>> | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/issue_101867.main.built.after.mir b/tests/mir-opt/building/issue_101867.main.built.after.mir index 19a777cb03b..0f7917dbb5c 100644 --- a/tests/mir-opt/building/issue_101867.main.built.after.mir +++ b/tests/mir-opt/building/issue_101867.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> -| 1: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> +| 0: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> +| 1: user_ty: Canonical { value: Ty(std::option::Option<u8>), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_101867.rs:4:12: 4:22, inferred_ty: std::option::Option<u8> | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir index e07c2b6fa9d..1855bb0787d 100644 --- a/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir +++ b/tests/mir-opt/building/receiver_ptr_mutability.main.built.after.mir @@ -1,10 +1,10 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test -| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test -| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test -| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test +| 0: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test +| 1: user_ty: Canonical { value: Ty(*mut Test), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:15:14: 15:23, inferred_ty: *mut Test +| 2: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test +| 3: user_ty: Canonical { value: Ty(&&&&*mut Test), max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], defining_opaque_types: [] }, span: $DIR/receiver_ptr_mutability.rs:19:18: 19:31, inferred_ty: &&&&*mut Test | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff index 7a374c5675a..4af3ed3e1d1 100644 --- a/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -12,8 +12,6 @@ let mut _7: isize; let _8: u32; let _9: u32; -+ let mut _10: isize; -+ let mut _11: bool; scope 1 { debug a => _8; debug b => _9; @@ -29,28 +27,20 @@ StorageDead(_5); StorageDead(_4); _7 = discriminant((_3.0: std::option::Option<u32>)); -- switchInt(move _7) -> [1: bb2, otherwise: bb1]; -+ StorageLive(_10); -+ _10 = discriminant((_3.1: std::option::Option<u32>)); -+ StorageLive(_11); -+ _11 = Ne(_7, move _10); -+ StorageDead(_10); -+ switchInt(move _11) -> [0: bb4, otherwise: bb1]; + switchInt(move _7) -> [1: bb2, 0: bb1, otherwise: bb5]; } bb1: { -+ StorageDead(_11); _0 = const 1_u32; -- goto -> bb4; -+ goto -> bb3; + goto -> bb4; } bb2: { -- _6 = discriminant((_3.1: std::option::Option<u32>)); -- switchInt(move _6) -> [1: bb3, otherwise: bb1]; -- } -- -- bb3: { + _6 = discriminant((_3.1: std::option::Option<u32>)); + switchInt(move _6) -> [1: bb3, 0: bb1, otherwise: bb5]; + } + + bb3: { StorageLive(_8); _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); StorageLive(_9); @@ -58,19 +48,16 @@ _0 = const 0_u32; StorageDead(_9); StorageDead(_8); -- goto -> bb4; -+ goto -> bb3; + goto -> bb4; } -- bb4: { -+ bb3: { + bb4: { StorageDead(_3); return; -+ } -+ -+ bb4: { -+ StorageDead(_11); -+ switchInt(_7) -> [1: bb2, otherwise: bb1]; + } + + bb5: { + unreachable; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff index 1348bdd739a..7776ff0fde7 100644 --- a/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -13,8 +13,6 @@ let mut _8: isize; let _9: u32; let _10: u32; -+ let mut _11: isize; -+ let mut _12: bool; scope 1 { debug a => _9; debug b => _10; @@ -30,33 +28,25 @@ StorageDead(_5); StorageDead(_4); _8 = discriminant((_3.0: std::option::Option<u32>)); -- switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb1]; -+ StorageLive(_11); -+ _11 = discriminant((_3.1: std::option::Option<u32>)); -+ StorageLive(_12); -+ _12 = Ne(_8, move _11); -+ StorageDead(_11); -+ switchInt(move _12) -> [0: bb5, otherwise: bb1]; + switchInt(move _8) -> [0: bb3, 1: bb2, otherwise: bb7]; } bb1: { -+ StorageDead(_12); _0 = const 1_u32; -- goto -> bb6; -+ goto -> bb4; + goto -> bb6; } bb2: { -- _6 = discriminant((_3.1: std::option::Option<u32>)); -- switchInt(move _6) -> [1: bb4, otherwise: bb1]; -- } -- -- bb3: { -- _7 = discriminant((_3.1: std::option::Option<u32>)); -- switchInt(move _7) -> [0: bb5, otherwise: bb1]; -- } -- -- bb4: { + _6 = discriminant((_3.1: std::option::Option<u32>)); + switchInt(move _6) -> [1: bb4, 0: bb1, otherwise: bb7]; + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option<u32>)); + switchInt(move _7) -> [0: bb5, 1: bb1, otherwise: bb7]; + } + + bb4: { StorageLive(_9); _9 = (((_3.0: std::option::Option<u32>) as Some).0: u32); StorageLive(_10); @@ -64,26 +54,21 @@ _0 = const 0_u32; StorageDead(_10); StorageDead(_9); -- goto -> bb6; -+ goto -> bb4; + goto -> bb6; } -- bb5: { -+ bb3: { - _0 = const 0_u32; -- goto -> bb6; -+ goto -> bb4; + bb5: { + _0 = const 2_u32; + goto -> bb6; } -- bb6: { -+ bb4: { + bb6: { StorageDead(_3); return; -+ } -+ -+ bb5: { -+ StorageDead(_12); -+ switchInt(_8) -> [0: bb3, 1: bb2, otherwise: bb1]; + } + + bb7: { + unreachable; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff index e058c409cb5..b41e952d80f 100644 --- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff @@ -1,76 +1,107 @@ - // MIR for `opt3` before EarlyOtherwiseBranch + // MIR for `opt3` after EarlyOtherwiseBranch - fn opt3(_1: Option<u32>, _2: Option<bool>) -> u32 { + fn opt3(_1: Option2<u32>, _2: Option2<bool>) -> u32 { debug x => _1; debug y => _2; let mut _0: u32; - let mut _3: (std::option::Option<u32>, std::option::Option<bool>); - let mut _4: std::option::Option<u32>; - let mut _5: std::option::Option<bool>; + let mut _3: (Option2<u32>, Option2<bool>); + let mut _4: Option2<u32>; + let mut _5: Option2<bool>; let mut _6: isize; let mut _7: isize; - let _8: u32; - let _9: bool; -+ let mut _10: isize; -+ let mut _11: bool; + let mut _8: isize; + let mut _9: isize; + let _10: u32; + let _11: bool; ++ let mut _12: isize; ++ let mut _13: bool; scope 1 { - debug a => _8; - debug b => _9; + debug a => _10; + debug b => _11; } bb0: { StorageLive(_3); StorageLive(_4); - _4 = _1; + _4 = move _1; StorageLive(_5); - _5 = _2; + _5 = move _2; _3 = (move _4, move _5); StorageDead(_5); StorageDead(_4); - _7 = discriminant((_3.0: std::option::Option<u32>)); -- switchInt(move _7) -> [1: bb2, otherwise: bb1]; -+ StorageLive(_10); -+ _10 = discriminant((_3.1: std::option::Option<bool>)); -+ StorageLive(_11); -+ _11 = Ne(_7, move _10); -+ StorageDead(_10); -+ switchInt(move _11) -> [0: bb4, otherwise: bb1]; + _9 = discriminant((_3.0: Option2<u32>)); +- switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; ++ StorageLive(_12); ++ _12 = discriminant((_3.1: Option2<bool>)); ++ StorageLive(_13); ++ _13 = Ne(_9, move _12); ++ StorageDead(_12); ++ switchInt(move _13) -> [0: bb7, otherwise: bb1]; } bb1: { -+ StorageDead(_11); ++ StorageDead(_13); _0 = const 1_u32; -- goto -> bb4; -+ goto -> bb3; +- goto -> bb8; ++ goto -> bb5; } bb2: { -- _6 = discriminant((_3.1: std::option::Option<bool>)); -- switchInt(move _6) -> [1: bb3, otherwise: bb1]; +- _6 = discriminant((_3.1: Option2<bool>)); +- switchInt(move _6) -> [0: bb5, otherwise: bb1]; - } - - bb3: { - StorageLive(_8); - _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); - StorageLive(_9); - _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool); +- _7 = discriminant((_3.1: Option2<bool>)); +- switchInt(move _7) -> [1: bb6, otherwise: bb1]; +- } +- +- bb4: { +- _8 = discriminant((_3.1: Option2<bool>)); +- switchInt(move _8) -> [2: bb7, otherwise: bb1]; +- } +- +- bb5: { + StorageLive(_10); + _10 = (((_3.0: Option2<u32>) as Some).0: u32); + StorageLive(_11); + _11 = (((_3.1: Option2<bool>) as Some).0: bool); _0 = const 0_u32; - StorageDead(_9); - StorageDead(_8); -- goto -> bb4; -+ goto -> bb3; + StorageDead(_11); + StorageDead(_10); +- goto -> bb8; ++ goto -> bb5; } -- bb4: { +- bb6: { + bb3: { + _0 = const 2_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb7: { ++ bb4: { + _0 = const 3_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb8: { ++ bb5: { StorageDead(_3); return; + } + +- bb9: { ++ bb6: { + unreachable; + } + -+ bb4: { -+ StorageDead(_11); -+ switchInt(_7) -> [1: bb2, otherwise: bb1]; ++ bb7: { ++ StorageDead(_13); ++ switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6]; } } diff --git a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..18dea56f430 --- /dev/null +++ b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff @@ -0,0 +1,107 @@ +- // MIR for `opt4` before EarlyOtherwiseBranch ++ // MIR for `opt4` after EarlyOtherwiseBranch + + fn opt4(_1: Option2<u32>, _2: Option2<u32>) -> u32 { + debug x => _1; + debug y => _2; + let mut _0: u32; + let mut _3: (Option2<u32>, Option2<u32>); + let mut _4: Option2<u32>; + let mut _5: Option2<u32>; + let mut _6: isize; + let mut _7: isize; + let mut _8: isize; + let mut _9: isize; + let _10: u32; + let _11: u32; ++ let mut _12: isize; ++ let mut _13: bool; + scope 1 { + debug a => _10; + debug b => _11; + } + + bb0: { + StorageLive(_3); + StorageLive(_4); + _4 = move _1; + StorageLive(_5); + _5 = move _2; + _3 = (move _4, move _5); + StorageDead(_5); + StorageDead(_4); + _9 = discriminant((_3.0: Option2<u32>)); +- switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; ++ StorageLive(_12); ++ _12 = discriminant((_3.1: Option2<u32>)); ++ StorageLive(_13); ++ _13 = Ne(_9, move _12); ++ StorageDead(_12); ++ switchInt(move _13) -> [0: bb7, otherwise: bb1]; + } + + bb1: { ++ StorageDead(_13); + _0 = const 1_u32; +- goto -> bb8; ++ goto -> bb5; + } + + bb2: { +- _6 = discriminant((_3.1: Option2<u32>)); +- switchInt(move _6) -> [0: bb5, otherwise: bb1]; +- } +- +- bb3: { +- _7 = discriminant((_3.1: Option2<u32>)); +- switchInt(move _7) -> [1: bb6, otherwise: bb1]; +- } +- +- bb4: { +- _8 = discriminant((_3.1: Option2<u32>)); +- switchInt(move _8) -> [2: bb7, otherwise: bb1]; +- } +- +- bb5: { + StorageLive(_10); + _10 = (((_3.0: Option2<u32>) as Some).0: u32); + StorageLive(_11); + _11 = (((_3.1: Option2<u32>) as Some).0: u32); + _0 = const 0_u32; + StorageDead(_11); + StorageDead(_10); +- goto -> bb8; ++ goto -> bb5; + } + +- bb6: { ++ bb3: { + _0 = const 2_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb7: { ++ bb4: { + _0 = const 3_u32; +- goto -> bb8; ++ goto -> bb5; + } + +- bb8: { ++ bb5: { + StorageDead(_3); + return; + } + +- bb9: { ++ bb6: { + unreachable; ++ } ++ ++ bb7: { ++ StorageDead(_13); ++ switchInt(_9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb6]; + } + } + diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs index c984c271ccd..bfeb1f7bbc6 100644 --- a/tests/mir-opt/early_otherwise_branch.rs +++ b/tests/mir-opt/early_otherwise_branch.rs @@ -1,27 +1,79 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching + +enum Option2<T> { + Some(T), + None, + Other, +} + +// We can't optimize it because y may be an invalid value. // EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff fn opt1(x: Option<u32>, y: Option<u32>) -> u32 { + // CHECK-LABEL: fn opt1( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y) { (Some(a), Some(b)) => 0, _ => 1, } } +// FIXME: `switchInt` will have three targets after `UnreachableEnumBranching`, +// otherwise is unreachable. We can consume the UB fact to transform back to if else pattern. // EMIT_MIR early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff fn opt2(x: Option<u32>, y: Option<u32>) -> u32 { + // CHECK-LABEL: fn opt2( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y) { (Some(a), Some(b)) => 0, - (None, None) => 0, + (None, None) => 2, _ => 1, } } // optimize despite different types // EMIT_MIR early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff -fn opt3(x: Option<u32>, y: Option<bool>) -> u32 { +fn opt3(x: Option2<u32>, y: Option2<bool>) -> u32 { + // CHECK-LABEL: fn opt3( + // CHECK: let mut [[CMP_LOCAL:_.*]]: bool; + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}}); + // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]); + // CHECK: switchInt(move [[CMP_LOCAL]]) -> [ + // CHECK-NEXT: } match (x, y) { - (Some(a), Some(b)) => 0, + (Option2::Some(a), Option2::Some(b)) => 0, + (Option2::None, Option2::None) => 2, + (Option2::Other, Option2::Other) => 3, + _ => 1, + } +} + +// EMIT_MIR early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff +fn opt4(x: Option2<u32>, y: Option2<u32>) -> u32 { + // CHECK-LABEL: fn opt4( + // CHECK: let mut [[CMP_LOCAL:_.*]]: bool; + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}}); + // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]); + // CHECK: switchInt(move [[CMP_LOCAL]]) -> [ + // CHECK-NEXT: } + match (x, y) { + (Option2::Some(a), Option2::Some(b)) => 0, + (Option2::None, Option2::None) => 2, + (Option2::Other, Option2::Other) => 3, _ => 1, } } @@ -29,5 +81,6 @@ fn opt3(x: Option<u32>, y: Option<bool>) -> u32 { fn main() { opt1(None, Some(0)); opt2(None, Some(0)); - opt3(None, Some(false)); + opt3(Option2::None, Option2::Some(false)); + opt4(Option2::None, Option2::Some(0)); } diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff index f98d68e6ffc..4c3c717b522 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -13,17 +13,15 @@ let mut _8: isize; let mut _9: isize; let mut _10: isize; - let _11: u32; - let _12: u32; + let mut _11: isize; + let mut _12: isize; let _13: u32; -+ let mut _14: isize; -+ let mut _15: bool; -+ let mut _16: isize; -+ let mut _17: bool; + let _14: u32; + let _15: u32; scope 1 { - debug a => _11; - debug b => _12; - debug c => _13; + debug a => _13; + debug b => _14; + debug c => _15; } bb0: { @@ -38,60 +36,61 @@ StorageDead(_7); StorageDead(_6); StorageDead(_5); - _10 = discriminant((_4.0: std::option::Option<u32>)); -- switchInt(move _10) -> [1: bb2, otherwise: bb1]; -+ StorageLive(_14); -+ _14 = discriminant((_4.1: std::option::Option<u32>)); -+ StorageLive(_15); -+ _15 = Ne(_10, move _14); -+ StorageDead(_14); -+ switchInt(move _15) -> [0: bb5, otherwise: bb1]; + _12 = discriminant((_4.0: std::option::Option<u32>)); + switchInt(move _12) -> [0: bb4, 1: bb2, otherwise: bb9]; } bb1: { -+ StorageDead(_17); -+ StorageDead(_15); _0 = const 1_u32; -- goto -> bb5; -+ goto -> bb4; + goto -> bb8; } bb2: { -- _9 = discriminant((_4.1: std::option::Option<u32>)); -- switchInt(move _9) -> [1: bb3, otherwise: bb1]; -- } -- -- bb3: { + _9 = discriminant((_4.1: std::option::Option<u32>)); + switchInt(move _9) -> [1: bb3, 0: bb1, otherwise: bb9]; + } + + bb3: { _8 = discriminant((_4.2: std::option::Option<u32>)); -- switchInt(move _8) -> [1: bb4, otherwise: bb1]; -+ switchInt(move _8) -> [1: bb3, otherwise: bb1]; + switchInt(move _8) -> [1: bb6, 0: bb1, otherwise: bb9]; + } + + bb4: { + _11 = discriminant((_4.1: std::option::Option<u32>)); + switchInt(move _11) -> [0: bb5, 1: bb1, otherwise: bb9]; + } + + bb5: { + _10 = discriminant((_4.2: std::option::Option<u32>)); + switchInt(move _10) -> [0: bb7, 1: bb1, otherwise: bb9]; } -- bb4: { -+ bb3: { - StorageLive(_11); - _11 = (((_4.0: std::option::Option<u32>) as Some).0: u32); - StorageLive(_12); - _12 = (((_4.1: std::option::Option<u32>) as Some).0: u32); + bb6: { StorageLive(_13); - _13 = (((_4.2: std::option::Option<u32>) as Some).0: u32); + _13 = (((_4.0: std::option::Option<u32>) as Some).0: u32); + StorageLive(_14); + _14 = (((_4.1: std::option::Option<u32>) as Some).0: u32); + StorageLive(_15); + _15 = (((_4.2: std::option::Option<u32>) as Some).0: u32); _0 = const 0_u32; + StorageDead(_15); + StorageDead(_14); StorageDead(_13); - StorageDead(_12); - StorageDead(_11); -- goto -> bb5; -+ goto -> bb4; + goto -> bb8; + } + + bb7: { + _0 = const 2_u32; + goto -> bb8; } -- bb5: { -+ bb4: { + bb8: { StorageDead(_4); return; -+ } -+ -+ bb5: { -+ StorageDead(_15); -+ switchInt(_10) -> [1: bb2, otherwise: bb1]; + } + + bb9: { + unreachable; } } diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff new file mode 100644 index 00000000000..0ea7a10baaa --- /dev/null +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,141 @@ +- // MIR for `opt2` before EarlyOtherwiseBranch ++ // MIR for `opt2` after EarlyOtherwiseBranch + + fn opt2(_1: Option2<u32>, _2: Option2<u32>, _3: Option2<u32>) -> u32 { + debug x => _1; + debug y => _2; + debug z => _3; + let mut _0: u32; + let mut _4: (Option2<u32>, Option2<u32>, Option2<u32>); + let mut _5: Option2<u32>; + let mut _6: Option2<u32>; + let mut _7: Option2<u32>; + let mut _8: isize; + let mut _9: isize; + let mut _10: isize; + let mut _11: isize; + let mut _12: isize; + let mut _13: isize; + let mut _14: isize; + let _15: u32; + let _16: u32; + let _17: u32; ++ let mut _18: isize; ++ let mut _19: bool; + scope 1 { + debug a => _15; + debug b => _16; + debug c => _17; + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = move _1; + StorageLive(_6); + _6 = move _2; + StorageLive(_7); + _7 = move _3; + _4 = (move _5, move _6, move _7); + StorageDead(_7); + StorageDead(_6); + StorageDead(_5); + _14 = discriminant((_4.0: Option2<u32>)); +- switchInt(move _14) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb12]; ++ StorageLive(_18); ++ _18 = discriminant((_4.1: Option2<u32>)); ++ StorageLive(_19); ++ _19 = Ne(_14, move _18); ++ StorageDead(_18); ++ switchInt(move _19) -> [0: bb10, otherwise: bb1]; + } + + bb1: { ++ StorageDead(_19); + _0 = const 1_u32; +- goto -> bb11; ++ goto -> bb8; + } + + bb2: { +- _9 = discriminant((_4.1: Option2<u32>)); +- switchInt(move _9) -> [0: bb3, otherwise: bb1]; +- } +- +- bb3: { + _8 = discriminant((_4.2: Option2<u32>)); +- switchInt(move _8) -> [0: bb8, otherwise: bb1]; ++ switchInt(move _8) -> [0: bb5, otherwise: bb1]; + } + +- bb4: { +- _11 = discriminant((_4.1: Option2<u32>)); +- switchInt(move _11) -> [1: bb5, otherwise: bb1]; +- } +- +- bb5: { ++ bb3: { + _10 = discriminant((_4.2: Option2<u32>)); +- switchInt(move _10) -> [1: bb9, otherwise: bb1]; ++ switchInt(move _10) -> [1: bb6, otherwise: bb1]; + } + +- bb6: { +- _13 = discriminant((_4.1: Option2<u32>)); +- switchInt(move _13) -> [2: bb7, otherwise: bb1]; +- } +- +- bb7: { ++ bb4: { + _12 = discriminant((_4.2: Option2<u32>)); +- switchInt(move _12) -> [2: bb10, otherwise: bb1]; ++ switchInt(move _12) -> [2: bb7, otherwise: bb1]; + } + +- bb8: { ++ bb5: { + StorageLive(_15); + _15 = (((_4.0: Option2<u32>) as Some).0: u32); + StorageLive(_16); + _16 = (((_4.1: Option2<u32>) as Some).0: u32); + StorageLive(_17); + _17 = (((_4.2: Option2<u32>) as Some).0: u32); + _0 = const 0_u32; + StorageDead(_17); + StorageDead(_16); + StorageDead(_15); +- goto -> bb11; ++ goto -> bb8; + } + +- bb9: { ++ bb6: { + _0 = const 2_u32; +- goto -> bb11; ++ goto -> bb8; + } + +- bb10: { ++ bb7: { + _0 = const 3_u32; +- goto -> bb11; ++ goto -> bb8; + } + +- bb11: { ++ bb8: { + StorageDead(_4); + return; + } + +- bb12: { ++ bb9: { + unreachable; ++ } ++ ++ bb10: { ++ StorageDead(_19); ++ switchInt(_14) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9]; + } + } + diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs b/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs index 32081347558..2d215621bbd 100644 --- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs +++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.rs @@ -1,14 +1,49 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching +enum Option2<T> { + Some(T), + None, + Other, +} + +// FIXME: `switchInt` will have three targets after `UnreachableEnumBranching`, +// otherwise is unreachable. We can consume the UB fact to transform back to if else pattern. // EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff fn opt1(x: Option<u32>, y: Option<u32>, z: Option<u32>) -> u32 { + // CHECK-LABEL: fn opt1( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y, z) { (Some(a), Some(b), Some(c)) => 0, + (None, None, None) => 2, + _ => 1, + } +} + +// EMIT_MIR early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff +fn opt2(x: Option2<u32>, y: Option2<u32>, z: Option2<u32>) -> u32 { + // CHECK-LABEL: fn opt2( + // CHECK: let mut [[CMP_LOCAL:_.*]]: bool; + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK: [[LOCAL2:_.*]] = discriminant({{.*}}); + // CHECK: [[CMP_LOCAL]] = Ne([[LOCAL1]], move [[LOCAL2]]); + // CHECK: switchInt(move [[CMP_LOCAL]]) -> [ + // CHECK-NEXT: } + match (x, y, z) { + (Option2::Some(a), Option2::Some(b), Option2::Some(c)) => 0, + (Option2::None, Option2::None, Option2::None) => 2, + (Option2::Other, Option2::Other, Option2::Other) => 3, _ => 1, } } fn main() { opt1(None, Some(0), None); + opt2(Option2::None, Option2::Some(0), Option2::None); } diff --git a/tests/mir-opt/early_otherwise_branch_68867.rs b/tests/mir-opt/early_otherwise_branch_68867.rs index 805d21533c5..59bc19ceecc 100644 --- a/tests/mir-opt/early_otherwise_branch_68867.rs +++ b/tests/mir-opt/early_otherwise_branch_68867.rs @@ -1,5 +1,5 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching // FIXME: This test was broken by the derefer change. @@ -19,6 +19,13 @@ pub extern "C" fn try_sum( x: &ViewportPercentageLength, other: &ViewportPercentageLength, ) -> Result<ViewportPercentageLength, ()> { + // CHECK-LABEL: fn try_sum( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } use self::ViewportPercentageLength::*; Ok(match (x, other) { (&Vw(one), &Vw(other)) => Vw(one + other), diff --git a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff index a5b5659a31a..de12fe8f120 100644 --- a/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -78,7 +78,7 @@ StorageDead(_5); _34 = deref_copy (_4.0: &ViewportPercentageLength); _11 = discriminant((*_34)); - switchInt(move _11) -> [0: bb2, 1: bb3, 2: bb4, 3: bb5, otherwise: bb1]; + switchInt(move _11) -> [0: bb2, 1: bb3, 2: bb4, 3: bb5, otherwise: bb12]; } bb1: { @@ -213,5 +213,9 @@ bb11: { return; } + + bb12: { + unreachable; + } } diff --git a/tests/mir-opt/early_otherwise_branch_noopt.rs b/tests/mir-opt/early_otherwise_branch_noopt.rs index 648089e2df1..6b48393e6b9 100644 --- a/tests/mir-opt/early_otherwise_branch_noopt.rs +++ b/tests/mir-opt/early_otherwise_branch_noopt.rs @@ -1,11 +1,18 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching // must not optimize as it does not follow the pattern of // left and right hand side being the same variant // EMIT_MIR early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff fn noopt1(x: Option<u32>, y: Option<u32>) -> u32 { + // CHECK-LABEL: fn noopt1( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match (x, y) { (Some(a), Some(b)) => 0, (Some(a), None) => 1, diff --git a/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff index b24ff6ec74b..8eab59823f4 100644 --- a/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff @@ -14,7 +14,7 @@ bb0: { _3 = discriminant(_1); - switchInt(move _3) -> [1: bb2, otherwise: bb1]; + switchInt(move _3) -> [1: bb2, 0: bb1, otherwise: bb6]; } bb1: { @@ -24,7 +24,7 @@ bb2: { _4 = discriminant((*_2)); - switchInt(move _4) -> [1: bb4, otherwise: bb3]; + switchInt(move _4) -> [1: bb4, 0: bb3, otherwise: bb6]; } bb3: { @@ -43,5 +43,9 @@ bb5: { return; } + + bb6: { + unreachable; + } } diff --git a/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff index c3ea975ce03..6a4c947b882 100644 --- a/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff +++ b/tests/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff @@ -12,13 +12,13 @@ bb0: { _3 = discriminant((*_1)); - switchInt(move _3) -> [1: bb1, otherwise: bb3]; + switchInt(move _3) -> [1: bb1, 0: bb3, otherwise: bb5]; } bb1: { _4 = deref_copy (((*_1) as Some).0: &E<'_>); _2 = discriminant((*_4)); - switchInt(move _2) -> [1: bb2, otherwise: bb3]; + switchInt(move _2) -> [1: bb2, 0: bb3, otherwise: bb5]; } bb2: { @@ -34,5 +34,9 @@ bb4: { return; } + + bb5: { + unreachable; + } } diff --git a/tests/mir-opt/early_otherwise_branch_soundness.rs b/tests/mir-opt/early_otherwise_branch_soundness.rs index b4f5821c420..74a2af884c0 100644 --- a/tests/mir-opt/early_otherwise_branch_soundness.rs +++ b/tests/mir-opt/early_otherwise_branch_soundness.rs @@ -1,5 +1,5 @@ -// skip-filecheck //@ unit-test: EarlyOtherwiseBranch +//@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching // Tests various cases that the `early_otherwise_branch` opt should *not* optimize @@ -11,12 +11,26 @@ enum E<'a> { // EMIT_MIR early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff fn no_downcast(e: &E) -> u32 { + // CHECK-LABEL: fn no_downcast( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } if let E::Some(E::Some(_)) = e { 1 } else { 2 } } // SAFETY: if `a` is `Some`, `b` must point to a valid, initialized value // EMIT_MIR early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 { + // CHECK-LABEL: fn no_deref_ptr( + // CHECK: bb0: { + // CHECK: [[LOCAL1:_.*]] = discriminant({{.*}}); + // CHECK-NOT: Ne + // CHECK-NOT: discriminant + // CHECK: switchInt(move [[LOCAL1]]) -> [ + // CHECK-NEXT: } match a { // `*b` being correct depends on `a == Some(_)` Some(_) => match *b { diff --git a/tests/mir-opt/issue_72181_1.main.built.after.mir b/tests/mir-opt/issue_72181_1.main.built.after.mir index ae0dc9a0b6a..e8ad5cd8d16 100644 --- a/tests/mir-opt/issue_72181_1.main.built.after.mir +++ b/tests/mir-opt/issue_72181_1.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void -| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 0: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void +| 1: user_ty: Canonical { value: Ty(Void), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_72181_1.rs:17:12: 17:16, inferred_ty: Void | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.32bit.mir b/tests/mir-opt/issue_99325.main.built.after.32bit.mir index c8039dc4735..0b0bac73e9f 100644 --- a/tests/mir-opt/issue_99325.main.built.after.32bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.32bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/issue_99325.main.built.after.64bit.mir b/tests/mir-opt/issue_99325.main.built.after.64bit.mir index c8039dc4735..0b0bac73e9f 100644 --- a/tests/mir-opt/issue_99325.main.built.after.64bit.mir +++ b/tests/mir-opt/issue_99325.main.built.after.64bit.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [&*b"AAAA"], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:13:16: 13:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[d56d]::function_with_bytes), UserArgs { args: [UnevaluatedConst { def: DefId(0:8 ~ issue_99325[d56d]::main::{constant#1}), args: [] }: &'static [u8; 4_usize]], user_self_ty: None }), max_universe: U0, variables: [], defining_opaque_types: [] }, span: $DIR/issue_99325.rs:14:16: 14:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); diff --git a/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff new file mode 100644 index 00000000000..31ce51dc6de --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff @@ -0,0 +1,47 @@ +- // MIR for `match_i128_u128` before MatchBranchSimplification ++ // MIR for `match_i128_u128` after MatchBranchSimplification + + fn match_i128_u128(_1: EnumAi128) -> u128 { + debug i => _1; + let mut _0: u128; + let mut _2: i128; ++ let mut _3: i128; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [1: bb3, 2: bb4, 3: bb5, 340282366920938463463374607431768211455: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const core::num::<impl u128>::MAX; +- goto -> bb6; +- } +- +- bb3: { +- _0 = const 1_u128; +- goto -> bb6; +- } +- +- bb4: { +- _0 = const 2_u128; +- goto -> bb6; +- } +- +- bb5: { +- _0 = const 3_u128; +- goto -> bb6; +- } +- +- bb6: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u128 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff new file mode 100644 index 00000000000..e1b537b1b71 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_i16_i8` before MatchBranchSimplification ++ // MIR for `match_i16_i8` after MatchBranchSimplification + + fn match_i16_i8(_1: EnumAi16) -> i8 { + debug i => _1; + let mut _0: i8; + let mut _2: i16; ++ let mut _3: i16; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [65535: bb3, 2: bb4, 65533: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const -3_i8; +- goto -> bb5; +- } +- +- bb3: { +- _0 = const -1_i8; +- goto -> bb5; +- } +- +- bb4: { +- _0 = const 2_i8; +- goto -> bb5; +- } +- +- bb5: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff new file mode 100644 index 00000000000..cabc5a44cd8 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_i8_i16` before MatchBranchSimplification ++ // MIR for `match_i8_i16` after MatchBranchSimplification + + fn match_i8_i16(_1: EnumAi8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: i8; ++ let mut _3: i8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const -3_i16; +- goto -> bb5; +- } +- +- bb3: { +- _0 = const -1_i16; +- goto -> bb5; +- } +- +- bb4: { +- _0 = const 2_i16; +- goto -> bb5; +- } +- +- bb5: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff new file mode 100644 index 00000000000..b0217792294 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff @@ -0,0 +1,37 @@ +- // MIR for `match_i8_i16_failed` before MatchBranchSimplification ++ // MIR for `match_i8_i16_failed` after MatchBranchSimplification + + fn match_i8_i16_failed(_1: EnumAi8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: i8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [255: bb3, 2: bb4, 253: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 3_i16; + goto -> bb5; + } + + bb3: { + _0 = const -1_i16; + goto -> bb5; + } + + bb4: { + _0 = const 2_i16; + goto -> bb5; + } + + bb5: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff new file mode 100644 index 00000000000..9ee01a87a91 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff @@ -0,0 +1,37 @@ +- // MIR for `match_u8_i16` before MatchBranchSimplification ++ // MIR for `match_u8_i16` after MatchBranchSimplification + + fn match_u8_i16(_1: EnumAu8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: u8; ++ let mut _3: u8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 2_i16; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 1_i16; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff new file mode 100644 index 00000000000..3333cd765a8 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff @@ -0,0 +1,26 @@ +- // MIR for `match_u8_i16_2` before MatchBranchSimplification ++ // MIR for `match_u8_i16_2` after MatchBranchSimplification + + fn match_u8_i16_2(_1: EnumAu8) -> i16 { + let mut _0: i16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(_2) -> [1: bb3, 2: bb1, otherwise: bb2]; + } + + bb1: { + _0 = const 2_i16; + goto -> bb3; + } + + bb2: { + unreachable; + } + + bb3: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff new file mode 100644 index 00000000000..6da19e46dab --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff @@ -0,0 +1,32 @@ +- // MIR for `match_u8_i16_failed` before MatchBranchSimplification ++ // MIR for `match_u8_i16_failed` after MatchBranchSimplification + + fn match_u8_i16_failed(_1: EnumAu8) -> i16 { + debug i => _1; + let mut _0: i16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(move _2) -> [1: bb3, 2: bb2, otherwise: bb1]; + } + + bb1: { + unreachable; + } + + bb2: { + _0 = const 3_i16; + goto -> bb4; + } + + bb3: { + _0 = const 1_i16; + goto -> bb4; + } + + bb4: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff new file mode 100644 index 00000000000..8fa497fe890 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff @@ -0,0 +1,31 @@ +- // MIR for `match_u8_i16_fallback` before MatchBranchSimplification ++ // MIR for `match_u8_i16_fallback` after MatchBranchSimplification + + fn match_u8_i16_fallback(_1: u8) -> i16 { + debug i => _1; + let mut _0: i16; + + bb0: { + switchInt(_1) -> [1: bb2, 2: bb3, otherwise: bb1]; + } + + bb1: { + _0 = const 3_i16; + goto -> bb4; + } + + bb2: { + _0 = const 1_i16; + goto -> bb4; + } + + bb3: { + _0 = const 2_i16; + goto -> bb4; + } + + bb4: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff new file mode 100644 index 00000000000..aa9fcc60a3e --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff @@ -0,0 +1,42 @@ +- // MIR for `match_u8_u16` before MatchBranchSimplification ++ // MIR for `match_u8_u16` after MatchBranchSimplification + + fn match_u8_u16(_1: EnumBu8) -> u16 { + debug i => _1; + let mut _0: u16; + let mut _2: u8; ++ let mut _3: u8; + + bb0: { + _2 = discriminant(_1); +- switchInt(move _2) -> [1: bb3, 2: bb4, 5: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 5_u16; +- goto -> bb5; +- } +- +- bb3: { +- _0 = const 1_u16; +- goto -> bb5; +- } +- +- bb4: { +- _0 = const 2_u16; +- goto -> bb5; +- } +- +- bb5: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u16 (IntToInt); ++ StorageDead(_3); + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff new file mode 100644 index 00000000000..b47de6a52b7 --- /dev/null +++ b/tests/mir-opt/matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff @@ -0,0 +1,37 @@ +- // MIR for `match_u8_u16_2` before MatchBranchSimplification ++ // MIR for `match_u8_u16_2` after MatchBranchSimplification + + fn match_u8_u16_2(_1: EnumBu8) -> i16 { + let mut _0: i16; + let mut _2: u8; + + bb0: { + _2 = discriminant(_1); + switchInt(_2) -> [1: bb1, 2: bb2, 5: bb3, otherwise: bb4]; + } + + bb1: { + _0 = const 1_i16; + goto -> bb5; + } + + bb2: { + _0 = const 2_i16; + goto -> bb5; + } + + bb3: { + _0 = const 5_i16; + _0 = const 5_i16; + goto -> bb5; + } + + bb4: { + unreachable; + } + + bb5: { + return; + } + } + diff --git a/tests/mir-opt/matches_reduce_branches.rs b/tests/mir-opt/matches_reduce_branches.rs index 4bf14e5a7bd..ca3e5f747d1 100644 --- a/tests/mir-opt/matches_reduce_branches.rs +++ b/tests/mir-opt/matches_reduce_branches.rs @@ -1,18 +1,28 @@ -// skip-filecheck //@ unit-test: MatchBranchSimplification +#![feature(repr128)] +#![feature(core_intrinsics)] +#![feature(custom_mir)] -// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff -// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff -// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff +use std::intrinsics::mir::*; +// EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff fn foo(bar: Option<()>) { + // CHECK-LABEL: fn foo( + // CHECK: = Eq( + // CHECK: switchInt + // CHECK-NOT: switchInt if matches!(bar, None) { () } } +// EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff fn bar(i: i32) -> (bool, bool, bool, bool) { + // CHECK-LABEL: fn bar( + // CHECK: = Ne( + // CHECK: = Eq( + // CHECK-NOT: switchInt let a; let b; let c; @@ -38,7 +48,10 @@ fn bar(i: i32) -> (bool, bool, bool, bool) { (a, b, c, d) } +// EMIT_MIR matches_reduce_branches.match_nested_if.MatchBranchSimplification.diff fn match_nested_if() -> bool { + // CHECK-LABEL: fn match_nested_if( + // CHECK-NOT: switchInt let val = match () { () if if if if true { true } else { false } { true } else { false } { true @@ -53,9 +66,221 @@ fn match_nested_if() -> bool { val } +#[repr(u8)] +enum EnumAu8 { + A = 1, + B = 2, +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16.MatchBranchSimplification.diff +fn match_u8_i16(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_u8_i16( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as i16 (IntToInt); + // CHECH: return + match i { + EnumAu8::A => 1, + EnumAu8::B => 2, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16_2.MatchBranchSimplification.diff +// Check for different instruction lengths +#[custom_mir(dialect = "built")] +fn match_u8_i16_2(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_u8_i16_2( + // CHECK: switchInt + mir!( + { + let a = Discriminant(i); + match a { + 1 => bb1, + 2 => bb2, + _ => unreachable_bb, + } + } + bb1 = { + Goto(ret) + } + bb2 = { + RET = 2; + Goto(ret) + } + unreachable_bb = { + Unreachable() + } + ret = { + Return() + } + ) +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16_failed.MatchBranchSimplification.diff +fn match_u8_i16_failed(i: EnumAu8) -> i16 { + // CHECK-LABEL: fn match_u8_i16_failed( + // CHECK: switchInt + match i { + EnumAu8::A => 1, + EnumAu8::B => 3, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_i16_fallback.MatchBranchSimplification.diff +fn match_u8_i16_fallback(i: u8) -> i16 { + // CHECK-LABEL: fn match_u8_i16_fallback( + // CHECK: switchInt + match i { + 1 => 1, + 2 => 2, + _ => 3, + } +} + +#[repr(u8)] +enum EnumBu8 { + A = 1, + B = 2, + C = 5, +} + +// EMIT_MIR matches_reduce_branches.match_u8_u16.MatchBranchSimplification.diff +fn match_u8_u16(i: EnumBu8) -> u16 { + // CHECK-LABEL: fn match_u8_u16( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as u16 (IntToInt); + // CHECH: return + match i { + EnumBu8::A => 1, + EnumBu8::B => 2, + EnumBu8::C => 5, + } +} + +// EMIT_MIR matches_reduce_branches.match_u8_u16_2.MatchBranchSimplification.diff +// Check for different instruction lengths +#[custom_mir(dialect = "built")] +fn match_u8_u16_2(i: EnumBu8) -> i16 { + // CHECK-LABEL: fn match_u8_u16_2( + // CHECK: switchInt + mir!( + { + let a = Discriminant(i); + match a { + 1 => bb1, + 2 => bb2, + 5 => bb5, + _ => unreachable_bb, + } + } + bb1 = { + RET = 1; + Goto(ret) + } + bb2 = { + RET = 2; + Goto(ret) + } + bb5 = { + RET = 5; + RET = 5; + Goto(ret) + } + unreachable_bb = { + Unreachable() + } + ret = { + Return() + } + ) +} + +#[repr(i8)] +enum EnumAi8 { + A = -1, + B = 2, + C = -3, +} + +// EMIT_MIR matches_reduce_branches.match_i8_i16.MatchBranchSimplification.diff +fn match_i8_i16(i: EnumAi8) -> i16 { + // CHECK-LABEL: fn match_i8_i16( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as i16 (IntToInt); + // CHECH: return + match i { + EnumAi8::A => -1, + EnumAi8::B => 2, + EnumAi8::C => -3, + } +} + +// EMIT_MIR matches_reduce_branches.match_i8_i16_failed.MatchBranchSimplification.diff +fn match_i8_i16_failed(i: EnumAi8) -> i16 { + // CHECK-LABEL: fn match_i8_i16_failed( + // CHECK: switchInt + match i { + EnumAi8::A => -1, + EnumAi8::B => 2, + EnumAi8::C => 3, + } +} + +#[repr(i16)] +enum EnumAi16 { + A = -1, + B = 2, + C = -3, +} + +// EMIT_MIR matches_reduce_branches.match_i16_i8.MatchBranchSimplification.diff +fn match_i16_i8(i: EnumAi16) -> i8 { + // CHECK-LABEL: fn match_i16_i8( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as i8 (IntToInt); + // CHECH: return + match i { + EnumAi16::A => -1, + EnumAi16::B => 2, + EnumAi16::C => -3, + } +} + +#[repr(i128)] +enum EnumAi128 { + A = 1, + B = 2, + C = 3, + D = -1, +} + +// EMIT_MIR matches_reduce_branches.match_i128_u128.MatchBranchSimplification.diff +fn match_i128_u128(i: EnumAi128) -> u128 { + // CHECK-LABEL: fn match_i128_u128( + // CHECK-NOT: switchInt + // CHECK: _0 = _3 as u128 (IntToInt); + // CHECH: return + match i { + EnumAi128::A => 1, + EnumAi128::B => 2, + EnumAi128::C => 3, + EnumAi128::D => u128::MAX, + } +} + fn main() { let _ = foo(None); let _ = foo(Some(())); let _ = bar(0); let _ = match_nested_if(); + let _ = match_u8_i16(EnumAu8::A); + let _ = match_u8_i16_2(EnumAu8::A); + let _ = match_u8_i16_failed(EnumAu8::A); + let _ = match_u8_i16_fallback(1); + let _ = match_u8_u16(EnumBu8::A); + let _ = match_u8_u16_2(EnumBu8::A); + let _ = match_i8_i16(EnumAi8::A); + let _ = match_i8_i16_failed(EnumAi8::A); + let _ = match_i8_i16(EnumAi8::A); + let _ = match_i16_i8(EnumAi16::A); + let _ = match_i128_u128(EnumAi128::A); } diff --git a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff index 157f9c98353..11a18f58e3a 100644 --- a/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff @@ -5,27 +5,32 @@ debug e => _1; let mut _0: u8; let mut _2: isize; ++ let mut _3: isize; bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 1_u8; - goto -> bb4; - } - - bb3: { - _0 = const 0_u8; - goto -> bb4; - } - - bb4: { +- switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 1_u8; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 0_u8; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as u8 (IntToInt); ++ StorageDead(_3); return; } } diff --git a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff index 19083771fd9..809badc41ba 100644 --- a/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff +++ b/tests/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff @@ -5,27 +5,32 @@ debug e => _1; let mut _0: i8; let mut _2: isize; ++ let mut _3: isize; bb0: { _2 = discriminant(_1); - switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; - } - - bb1: { - unreachable; - } - - bb2: { - _0 = const 1_i8; - goto -> bb4; - } - - bb3: { - _0 = const 0_i8; - goto -> bb4; - } - - bb4: { +- switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1]; +- } +- +- bb1: { +- unreachable; +- } +- +- bb2: { +- _0 = const 1_i8; +- goto -> bb4; +- } +- +- bb3: { +- _0 = const 0_i8; +- goto -> bb4; +- } +- +- bb4: { ++ StorageLive(_3); ++ _3 = move _2; ++ _0 = _3 as i8 (IntToInt); ++ StorageDead(_3); return; } } diff --git a/tests/run-make/artifact-incr-cache/lib.rs b/tests/run-make/artifact-incr-cache/lib.rs new file mode 100644 index 00000000000..fa4048594e3 --- /dev/null +++ b/tests/run-make/artifact-incr-cache/lib.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +#[inline(never)] +pub fn add(a: u32, b: u32) -> u32 { + a + b +} diff --git a/tests/run-make/artifact-incr-cache/rmake.rs b/tests/run-make/artifact-incr-cache/rmake.rs new file mode 100644 index 00000000000..bb651368081 --- /dev/null +++ b/tests/run-make/artifact-incr-cache/rmake.rs @@ -0,0 +1,25 @@ +// rustc should be able to emit required files (asm, llvm-*, etc) during incremental +// compilation on the first pass by running the code gen as well as on subsequent runs - +// extracting them from the cache +// +// Fixes: rust-lang/rust#89149 +// Fixes: rust-lang/rust#88829 +// Also see discussion at +// <https://internals.rust-lang.org/t/interaction-between-incremental-compilation-and-emit/20551> + +extern crate run_make_support; + +use run_make_support::{rustc, tmp_dir}; + +fn main() { + let inc_dir = tmp_dir(); + + for _ in 0..=1 { + rustc() + .input("lib.rs") + .crate_type("lib") + .emit("obj,asm,dep-info,link,mir,llvm-ir,llvm-bc") + .incremental(&inc_dir) + .run(); + } +} diff --git a/tests/run-make/cross-lang-lto-riscv-abi/cstart.c b/tests/run-make/cross-lang-lto-riscv-abi/cstart.c new file mode 100644 index 00000000000..660469b75a8 --- /dev/null +++ b/tests/run-make/cross-lang-lto-riscv-abi/cstart.c @@ -0,0 +1,5 @@ +extern void hello(); + +void _start() { + hello(); +} diff --git a/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs new file mode 100644 index 00000000000..c31cf27f9ae --- /dev/null +++ b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs @@ -0,0 +1,9 @@ +#![allow(internal_features)] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +trait Sized {} + +#[no_mangle] +pub fn hello() {} diff --git a/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs new file mode 100644 index 00000000000..2f13cf17169 --- /dev/null +++ b/tests/run-make/cross-lang-lto-riscv-abi/rmake.rs @@ -0,0 +1,74 @@ +//! Make sure that cross-language LTO works on riscv targets, +//! which requires extra abi metadata to be emitted. +//@ needs-matching-clang +//@ needs-llvm-components riscv +extern crate run_make_support; + +use run_make_support::{bin_name, rustc, tmp_dir}; +use std::{ + env, + path::PathBuf, + process::{Command, Output}, + str, +}; + +fn handle_failed_output(output: Output) { + eprintln!("output status: `{}`", output.status); + eprintln!("=== STDOUT ===\n{}\n\n", String::from_utf8(output.stdout).unwrap()); + eprintln!("=== STDERR ===\n{}\n\n", String::from_utf8(output.stderr).unwrap()); + std::process::exit(1) +} + +fn check_target(target: &str, clang_target: &str, carch: &str, is_double_float: bool) { + eprintln!("Checking target {target}"); + // Rust part + rustc() + .input("riscv-xlto.rs") + .crate_type("rlib") + .target(target) + .panic("abort") + .linker_plugin_lto("on") + .run(); + // C part + let clang = env::var("CLANG").unwrap(); + let mut cmd = Command::new(clang); + let executable = tmp_dir().join("riscv-xlto"); + cmd.arg("-target") + .arg(clang_target) + .arg(format!("-march={carch}")) + .arg(format!("-flto=thin")) + .arg(format!("-fuse-ld=lld")) + .arg("-nostdlib") + .arg("-o") + .arg(&executable) + .arg("cstart.c") + .arg(tmp_dir().join("libriscv_xlto.rlib")); + eprintln!("{cmd:?}"); + let output = cmd.output().unwrap(); + if !output.status.success() { + handle_failed_output(output); + } + // Check that the built binary has correct float abi + let llvm_readobj = + PathBuf::from(env::var("LLVM_BIN_DIR").unwrap()).join(bin_name("llvm-readobj")); + let mut cmd = Command::new(llvm_readobj); + cmd.arg("--file-header").arg(executable); + eprintln!("{cmd:?}"); + let output = cmd.output().unwrap(); + if output.status.success() { + assert!( + !(is_double_float + ^ dbg!(str::from_utf8(&output.stdout).unwrap()) + .contains("EF_RISCV_FLOAT_ABI_DOUBLE")) + ) + } else { + handle_failed_output(output); + } +} + +fn main() { + check_target("riscv64gc-unknown-linux-gnu", "riscv64-linux-gnu", "rv64gc", true); + check_target("riscv64imac-unknown-none-elf", "riscv64-unknown-elf", "rv64imac", false); + check_target("riscv32imac-unknown-none-elf", "riscv32-unknown-elf", "rv32imac", false); + check_target("riscv32gc-unknown-linux-gnu", "riscv32-linux-gnu", "rv32gc", true); +} diff --git a/tests/run-make/exit-code/Makefile b/tests/run-make/exit-code/Makefile deleted file mode 100644 index 155e5cd1123..00000000000 --- a/tests/run-make/exit-code/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) success.rs; [ $$? -eq 0 ] - $(RUSTC) --invalid-arg-foo; [ $$? -eq 1 ] - $(RUSTC) compile-error.rs; [ $$? -eq 1 ] - RUSTC_ICE=0 $(RUSTC) -Ztreat-err-as-bug compile-error.rs; [ $$? -eq 101 ] - $(RUSTDOC) -o $(TMPDIR)/exit-code success.rs; [ $$? -eq 0 ] - $(RUSTDOC) --invalid-arg-foo; [ $$? -eq 1 ] - $(RUSTDOC) compile-error.rs; [ $$? -eq 1 ] - $(RUSTDOC) lint-failure.rs; [ $$? -eq 1 ] diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs new file mode 100644 index 00000000000..f387626287e --- /dev/null +++ b/tests/run-make/exit-code/rmake.rs @@ -0,0 +1,43 @@ +// Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations + +extern crate run_make_support; + +use run_make_support::{rustc, rustdoc, tmp_dir}; + +fn main() { + rustc() + .arg("success.rs") + .run(); + + rustc() + .arg("--invalid-arg-foo") + .run_fail_assert_exit_code(1); + + rustc() + .arg("compile-error.rs") + .run_fail_assert_exit_code(1); + + rustc() + .env("RUSTC_ICE", "0") + .arg("-Ztreat-err-as-bug") + .arg("compile-error.rs") + .run_fail_assert_exit_code(101); + + rustdoc() + .arg("success.rs") + .arg("-o") + .arg(tmp_dir().join("exit-code")) + .run(); + + rustdoc() + .arg("--invalid-arg-foo") + .run_fail_assert_exit_code(1); + + rustdoc() + .arg("compile-error.rs") + .run_fail_assert_exit_code(1); + + rustdoc() + .arg("lint-failure.rs") + .run_fail_assert_exit_code(1); +} diff --git a/tests/run-make/version/Makefile b/tests/run-make/version/Makefile deleted file mode 100644 index 3a130545d69..00000000000 --- a/tests/run-make/version/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) -V - $(RUSTC) -vV - $(RUSTC) --version --verbose diff --git a/tests/rustdoc-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml index fc80932caba..348ce0c992f 100644 --- a/tests/rustdoc-gui/docblock-code-block-line-number.goml +++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml @@ -2,23 +2,25 @@ include: "utils.goml" go-to: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html" -// Otherwise, we can't check text color -show-text: true - // We check that without this setting, there is no line number displayed. assert-false: "pre.example-line-numbers" +// We set the setting to show the line numbers on code examples. +set-local-storage: {"rustdoc-line-numbers": "true"} +reload: +// We wait for the line numbers to be added into the DOM by the JS... +wait-for: "pre.example-line-numbers" + +// Otherwise, we can't check text color +show-text: true + // Let's now check some CSS properties... define-function: ( "check-colors", [theme, color], block { - // We now set the setting to show the line numbers on code examples. - set-local-storage: {"rustdoc-line-numbers": "true"} // Page will be reloaded in "switch-theme". call-function: ("switch-theme", {"theme": |theme|}) - // We wait for the line numbers to be added into the DOM by the JS... - wait-for: "pre.example-line-numbers" // If the test didn't fail, it means that it was found! assert-css: ( "pre.example-line-numbers", diff --git a/tests/rustdoc-gui/scrape-examples-toggle.goml b/tests/rustdoc-gui/scrape-examples-toggle.goml index a9d37048188..441895a7c0e 100644 --- a/tests/rustdoc-gui/scrape-examples-toggle.goml +++ b/tests/rustdoc-gui/scrape-examples-toggle.goml @@ -9,6 +9,7 @@ define-function: ( [theme, toggle_line_color, toggle_line_hover_color], block { call-function: ("switch-theme", {"theme": |theme|}) + reload: // Clicking "More examples..." will open additional examples assert-attribute-false: (".more-examples-toggle", {"open": ""}) @@ -21,6 +22,8 @@ define-function: ( ".toggle-line:hover .toggle-line-inner", {"background-color": |toggle_line_hover_color|}, ) + // We put the toggle in the original state. + click: ".more-examples-toggle" // Moving cursor away from the toggle line to prevent disrupting next test. move-cursor-to: ".search-input" }, diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index d4da23fa156..9825f92b453 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -1,6 +1,108 @@ // The goal of this test is to ensure the color of the text is the one expected. include: "utils.goml" + +define-function: ( + "check-search-color", + [ + theme, count_color, desc_color, path_color, bottom_border_color, keyword_color, + struct_color, associatedtype_color, tymethod_color, method_color, structfield_color, + structfield_hover_color, macro_color, fn_color, hover_path_color, hover_background, grey + ], + block { + call-function: ("switch-theme", {"theme": |theme|}) + + // Waiting for the search results to appear... + wait-for: "#search-tabs" + assert-css: ( + "#search-tabs > button > .count", + {"color": |count_color|}, + ALL, + ) + assert-css: ( + "//*[@class='desc'][text()='Just a normal struct.']", + {"color": |desc_color|}, + ) + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']", + {"color": |path_color|}, + ) + + // Checking the color of the bottom border. + assert-css: ( + ".search-results > a", + {"border-bottom-color": |bottom_border_color|} + ) + + store-value: (entry_color, |path_color|) // color of the search entry + store-value: (hover_entry_color, |hover_path_color|) // color of the hovered/focused search entry + store-value: (background_color, "transparent") + store-value: (hover_background_color, |hover_background|) + store-value: (grey, |grey|) + + call-function: ("check-result-color", { + "result_kind": "keyword", + "color": |keyword_color|, + "hover_color": |keyword_color|, + }) + call-function: ("check-result-color", { + "result_kind": "struct", + "color": |struct_color|, + "hover_color": |struct_color|, + }) + call-function: ("check-result-color", { + "result_kind": "associatedtype", + "color": |associatedtype_color|, + "hover_color": |associatedtype_color|, + }) + call-function: ("check-result-color", { + "result_kind": "tymethod", + "color": |tymethod_color|, + "hover_color": |tymethod_color|, + }) + call-function: ("check-result-color", { + "result_kind": "method", + "color": |method_color|, + "hover_color": |method_color|, + }) + call-function: ("check-result-color", { + "result_kind": "structfield", + "color": |structfield_color|, + "hover_color": |structfield_hover_color|, + }) + call-function: ("check-result-color", { + "result_kind": "macro", + "color": |macro_color|, + "hover_color": |macro_color|, + }) + call-function: ("check-result-color", { + "result_kind": "fn", + "color": |fn_color|, + "hover_color": |fn_color|, + }) + + // Checking the `<a>` container. + move-cursor-to: ".search-input" + focus: ".search-input" // To ensure the `<a>` container isn't focused or hovered. + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", + {"color": |path_color|, "background-color": "transparent"}, + ALL, + ) + + // Checking color and background on hover. + move-cursor-to: "//*[@class='desc'][text()='Just a normal struct.']" + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']", + {"color": |hover_path_color|}, + ) + assert-css: ( + "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", + {"color": |hover_path_color|, "background-color": |hover_background|}, + ) + } +) + define-function: ( "check-result-color", [result_kind, color, hover_color], @@ -44,325 +146,85 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=coo" show-text: true // Ayu theme -call-function: ("switch-theme", {"theme": "ayu"}) - -// Waiting for the search results to appear... -wait-for: "#search-tabs" -assert-css: ( - "#search-tabs > button > .count", - {"color": "#888"}, - ALL, -) -assert-css: ( - "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "#c5c5c5"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#0096cf"}, -) - -// Checking the color of the bottom border. -assert-css: ( - ".search-results > a", - {"border-bottom-color": "#aaa3"} -) - -store-value: (entry_color, "#0096cf") // color of the search entry -store-value: (hover_entry_color, "#fff") // color of the hovered/focused search entry -store-value: (background_color, "transparent") // background color -store-value: (hover_background_color, "#3c3c3c") // hover background color -store-value: (grey, "#999") - -call-function: ( - "check-result-color", { - "result_kind": "keyword", - "color": "#39afd7", - "hover_color": "#39afd7", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "struct", - "color": "#ffa0a5", - "hover_color": "#ffa0a5", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "associatedtype", - "color": "#39afd7", - "hover_color": "#39afd7", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "tymethod", - "color": "#fdd687", - "hover_color": "#fdd687", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "method", - "color": "#fdd687", - "hover_color": "#fdd687", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "structfield", - "color": "#0096cf", - "hover_color": "#fff", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "macro", - "color": "#a37acc", - "hover_color": "#a37acc", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "fn", - "color": "#fdd687", - "hover_color": "#fdd687", - }, -) - -// Checking the `<a>` container. -move-cursor-to: ".search-input" -focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#0096cf", "background-color": "transparent"}, - ALL, -) - -// Checking color and background on hover. -move-cursor-to: "//*[@class='desc'][text()='Just a normal struct.']" -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#fff"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#fff", "background-color": "#3c3c3c"}, -) +call-function: ("check-search-color", { + "theme": "ayu", + "count_color": "#888", + "desc_color": "#c5c5c5", + "path_color": "#0096cf", + "bottom_border_color": "#aaa3", + "keyword_color": "#39afd7", + "struct_color": "#ffa0a5", + "associatedtype_color": "#39afd7", + "tymethod_color": "#fdd687", + "method_color": "#fdd687", + "structfield_color": "#0096cf", + "structfield_hover_color": "#fff", + "macro_color": "#a37acc", + "fn_color": "#fdd687", + "hover_path_color": "#fff", + "hover_background": "#3c3c3c", + "grey": "#999", +}) // Dark theme -call-function: ("switch-theme", {"theme": "dark"}) - -// Waiting for the search results to appear... -wait-for: "#search-tabs" -assert-css: ( - "#search-tabs > button > .count", - {"color": "#888"}, - ALL, -) -assert-css: ( - "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "#ddd"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#ddd"}, -) - -// Checking the color of the bottom border. -assert-css: ( - ".search-results > a", - {"border-bottom-color": "#aaa3"} -) - -store-value: (entry_color, "#ddd") // color of the search entry -store-value: (hover_entry_color, "#ddd") // color of the hovered/focused search entry -store-value: (background_color, "transparent") // background color -store-value: (hover_background_color, "#616161") // hover background color -store-value: (grey, "#ccc") - -call-function: ( - "check-result-color", { - "result_kind": "keyword", - "color": "#d2991d", - "hover_color": "#d2991d", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "struct", - "color": "#2dbfb8", - "hover_color": "#2dbfb8", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "associatedtype", - "color": "#d2991d", - "hover_color": "#d2991d", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "tymethod", - "color": "#2bab63", - "hover_color": "#2bab63", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "method", - "color": "#2bab63", - "hover_color": "#2bab63", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "structfield", - "color": "#ddd", - "hover_color": "#ddd", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "macro", - "color": "#09bd00", - "hover_color": "#09bd00", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "fn", - "color": "#2bab63", - "hover_color": "#2bab63", - }, -) - -// Checking the `<a>` container. -move-cursor-to: ".search-input" -focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#ddd", "background-color": "transparent"}, -) +call-function: ("check-search-color", { + "theme": "dark", + "count_color": "#888", + "desc_color": "#ddd", + "path_color": "#ddd", + "bottom_border_color": "#aaa3", + "keyword_color": "#d2991d", + "struct_color": "#2dbfb8", + "associatedtype_color": "#d2991d", + "tymethod_color": "#2bab63", + "method_color": "#2bab63", + "structfield_color": "#ddd", + "structfield_hover_color": "#ddd", + "macro_color": "#09bd00", + "fn_color": "#2bab63", + "hover_path_color": "#ddd", + "hover_background": "#616161", + "grey": "#ccc", +}) // Light theme -call-function: ("switch-theme", {"theme": "light"}) - -// Waiting for the search results to appear... -wait-for: "#search-tabs" -assert-css: ( - "#search-tabs > button > .count", - {"color": "#888"}, - ALL, -) -assert-css: ( - "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "#000"}, -) -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']", - {"color": "#000"}, -) - -// Checking the color of the bottom border. -assert-css: ( - ".search-results > a", - {"border-bottom-color": "#aaa3"} -) - -store-value: (entry_color, "#000") // color of the search entry -store-value: (hover_entry_color, "#000") // color of the hovered/focused search entry -store-value: (background_color, "transparent") // background color -store-value: (hover_background_color, "#ccc") // hover background color -store-value: (grey, "#999") - -call-function: ( - "check-result-color", { - "result_kind": "keyword", - "color": "#3873ad", - "hover_color": "#3873ad", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "struct", - "color": "#ad378a", - "hover_color": "#ad378a", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "associatedtype", - "color": "#3873ad", - "hover_color": "#3873ad", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "tymethod", - "color": "#ad7c37", - "hover_color": "#ad7c37", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "method", - "color": "#ad7c37", - "hover_color": "#ad7c37", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "structfield", - "color": "#000", - "hover_color": "#000", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "macro", - "color": "#068000", - "hover_color": "#068000", - }, -) -call-function: ( - "check-result-color", { - "result_kind": "fn", - "color": "#ad7c37", - "hover_color": "#ad7c37", - }, -) - -// Checking the `<a>` container. -move-cursor-to: ".search-input" -focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. -assert-css: ( - "//*[@class='result-name']//*[text()='test_docs::']/ancestor::a", - {"color": "#000", "background-color": "transparent"}, -) +call-function: ("check-search-color", { + "theme": "light", + "count_color": "#888", + "desc_color": "#000", + "path_color": "#000", + "bottom_border_color": "#aaa3", + "keyword_color": "#3873ad", + "struct_color": "#ad378a", + "associatedtype_color": "#3873ad", + "tymethod_color": "#ad7c37", + "method_color": "#ad7c37", + "structfield_color": "#000", + "structfield_hover_color": "#000", + "macro_color": "#068000", + "fn_color": "#ad7c37", + "hover_path_color": "#000", + "hover_background": "#ccc", + "grey": "#999", +}) // Check the alias. go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" -// If the text isn't displayed, the browser doesn't compute color style correctly... -show-text: true + +write-into: (".search-input", "thisisanalias") +// To be SURE that the search will be run. +press-key: 'Enter' +// Waiting for the search results to appear... +wait-for: "#search-tabs" define-function: ( "check-alias", [theme, alias, grey], block { call-function: ("switch-theme", {"theme": |theme|}) - write-into: (".search-input", "thisisanalias") - // To be SURE that the search will be run. - press-key: 'Enter' - // Waiting for the search results to appear... - wait-for: "#search-tabs" // Checking that the colors for the alias element are the ones expected. assert-css: (".result-name .path .alias", {"color": |alias|}) assert-css: (".result-name .path .alias > .grey", {"color": |grey|}) - // Leave the search results to prevent reloading with an already filled search input. - press-key: "Escape" }, ) diff --git a/tests/rustdoc-gui/settings.goml b/tests/rustdoc-gui/settings.goml index 56d0f8624e8..0011e44ca59 100644 --- a/tests/rustdoc-gui/settings.goml +++ b/tests/rustdoc-gui/settings.goml @@ -36,7 +36,12 @@ wait-for: "#alternative-display #search" assert: "#main-content.hidden" // Now let's check the content of the settings menu. -call-function: ("switch-theme", {"theme": "dark"}) +// If we are on the settings page, the menu doesn't work the same so we set +// the theme manually. +set-local-storage: {"rustdoc-theme": "dark", "rustdoc-use-system-theme": "false"} +// We reload the page so the local storage settings are being used. +reload: + click: "#settings-menu" wait-for: "#settings" diff --git a/tests/rustdoc-gui/utils.goml b/tests/rustdoc-gui/utils.goml index d9f8726ec53..844dc98a537 100644 --- a/tests/rustdoc-gui/utils.goml +++ b/tests/rustdoc-gui/utils.goml @@ -4,8 +4,15 @@ define-function: ( [theme], block { // Set the theme. - set-local-storage: {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"} - // We reload the page so the local storage settings are being used. - reload: + // Open the settings menu. + click: "#settings-menu" + // Wait for the popover to appear... + wait-for: "#settings" + // Change the setting. + click: "#theme-"+ |theme| + // Close the popover. + click: "#settings-menu" + // Ensure that the local storage was correctly updated. + assert-local-storage: {"rustdoc-theme": |theme|} }, ) diff --git a/tests/rustdoc-ui/ice-bug-report-url.stderr b/tests/rustdoc-ui/ice-bug-report-url.stderr index 06a52691310..66622a7654c 100644 --- a/tests/rustdoc-ui/ice-bug-report-url.stderr +++ b/tests/rustdoc-ui/ice-bug-report-url.stderr @@ -12,6 +12,8 @@ error: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md +note: please make sure that you have updated to the latest nightly + note: rustc {version} running on {platform} query stack during panic: diff --git a/tests/rustdoc/primitive/primitive.rs b/tests/rustdoc/primitive/primitive.rs index 32af2636c18..4b89fd9dfb7 100644 --- a/tests/rustdoc/primitive/primitive.rs +++ b/tests/rustdoc/primitive/primitive.rs @@ -1,6 +1,8 @@ #![crate_name = "foo"] #![feature(rustc_attrs)] +#![feature(f16)] +#![feature(f128)] // @has foo/index.html '//h2[@id="primitives"]' 'Primitive Types' // @has foo/index.html '//a[@href="primitive.i32.html"]' 'i32' @@ -13,9 +15,19 @@ // @!has foo/index.html '//span' '🔒' #[rustc_doc_primitive = "i32"] /// this is a test! -mod i32{} +mod i32 {} // @has foo/primitive.bool.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' #[rustc_doc_primitive = "bool"] /// hello mod bool {} + +// @has foo/primitive.f16.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[rustc_doc_primitive = "f16"] +/// hello +mod f16 {} + +// @has foo/primitive.f128.html '//section[@id="main-content"]//div[@class="docblock"]//p' 'hello' +#[rustc_doc_primitive = "f128"] +/// hello +mod f128 {} diff --git a/tests/rustdoc/synthetic_auto/supertrait-bounds.rs b/tests/rustdoc/synthetic_auto/supertrait-bounds.rs new file mode 100644 index 00000000000..503e65d0f4f --- /dev/null +++ b/tests/rustdoc/synthetic_auto/supertrait-bounds.rs @@ -0,0 +1,14 @@ +// Check that we don't add bounds to synthetic auto trait impls that are +// already implied by the item (like supertrait bounds). + +// In this case we don't want to add the bounds `T: Copy` and `T: 'static` +// to the auto trait impl because they're implied by the bound `T: Bound` +// on the implementor `Type`. + +pub struct Type<T: Bound>(T); + +// @has supertrait_bounds/struct.Type.html +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//h3[@class="code-header"]' \ +// "impl<T> Send for Type<T>where T: Send," + +pub trait Bound: Copy + 'static {} diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs index 3152bf23ca5..f77b318039d 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.rs @@ -22,6 +22,7 @@ fn main() { TyKind::Foreign(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Str => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Array(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` + TyKind::Pat(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Slice(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::RawPtr(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` TyKind::Ref(..) => (), //~ ERROR usage of `ty::TyKind::<kind>` diff --git a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr index 2ff5aad95dd..53bf5cb1a82 100644 --- a/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr +++ b/tests/ui-fulldeps/internal-lints/ty_tykind_usage.stderr @@ -67,119 +67,125 @@ LL | TyKind::Array(..) => (), error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:25:9 | -LL | TyKind::Slice(..) => (), +LL | TyKind::Pat(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:26:9 | -LL | TyKind::RawPtr(..) => (), +LL | TyKind::Slice(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:27:9 | -LL | TyKind::Ref(..) => (), +LL | TyKind::RawPtr(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:28:9 | -LL | TyKind::FnDef(..) => (), +LL | TyKind::Ref(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:29:9 | -LL | TyKind::FnPtr(..) => (), +LL | TyKind::FnDef(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:30:9 | -LL | TyKind::Dynamic(..) => (), +LL | TyKind::FnPtr(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:31:9 | -LL | TyKind::Closure(..) => (), +LL | TyKind::Dynamic(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:32:9 | -LL | TyKind::CoroutineClosure(..) => (), +LL | TyKind::Closure(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:33:9 | -LL | TyKind::Coroutine(..) => (), +LL | TyKind::CoroutineClosure(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:34:9 | -LL | TyKind::CoroutineWitness(..) => (), +LL | TyKind::Coroutine(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:35:9 | -LL | TyKind::Never => (), +LL | TyKind::CoroutineWitness(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:36:9 | -LL | TyKind::Tuple(..) => (), +LL | TyKind::Never => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:37:9 | -LL | TyKind::Alias(..) => (), +LL | TyKind::Tuple(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:38:9 | -LL | TyKind::Param(..) => (), +LL | TyKind::Alias(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:39:9 | -LL | TyKind::Bound(..) => (), +LL | TyKind::Param(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:40:9 | -LL | TyKind::Placeholder(..) => (), +LL | TyKind::Bound(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:41:9 | -LL | TyKind::Infer(..) => (), +LL | TyKind::Placeholder(..) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` --> $DIR/ty_tykind_usage.rs:42:9 | +LL | TyKind::Infer(..) => (), + | ^^^^^^ help: try using `ty::<kind>` directly: `ty` + +error: usage of `ty::TyKind::<kind>` + --> $DIR/ty_tykind_usage.rs:43:9 + | LL | TyKind::Error(_) => (), | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind::<kind>` - --> $DIR/ty_tykind_usage.rs:47:12 + --> $DIR/ty_tykind_usage.rs:48:12 | LL | if let TyKind::Int(int_ty) = kind {} | ^^^^^^ help: try using `ty::<kind>` directly: `ty` error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:49:24 + --> $DIR/ty_tykind_usage.rs:50:24 | LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} | ^^^^^^^^^^ @@ -187,7 +193,7 @@ LL | fn ty_kind(ty_bad: TyKind<'_>, ty_good: Ty<'_>) {} = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:51:37 + --> $DIR/ty_tykind_usage.rs:52:37 | LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { | ^^^^^^^^^^^ @@ -195,7 +201,7 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { = help: try using `Ty` instead error: usage of `ty::TyKind` - --> $DIR/ty_tykind_usage.rs:51:53 + --> $DIR/ty_tykind_usage.rs:52:53 | LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { | ^^^^^^^^^^^ @@ -203,12 +209,12 @@ LL | fn ir_ty_kind<I: Interner>(bad: IrTyKind<I>) -> IrTyKind<I> { = help: try using `Ty` instead error: usage of `ty::TyKind::<kind>` - --> $DIR/ty_tykind_usage.rs:54:9 + --> $DIR/ty_tykind_usage.rs:55:9 | LL | IrTyKind::Bool | --------^^^^^^ | | | help: try using `ty::<kind>` directly: `ty` -error: aborting due to 33 previous errors +error: aborting due to 34 previous errors diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs new file mode 100644 index 00000000000..3b52d88de3c --- /dev/null +++ b/tests/ui-fulldeps/stable-mir/check_binop.rs @@ -0,0 +1,147 @@ +//@ run-pass +//! Test information regarding binary operations. + +//@ ignore-stage1 +//@ ignore-cross-compile +//@ ignore-remote +//@ ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837 + +#![feature(rustc_private)] + +extern crate rustc_hir; +#[macro_use] +extern crate rustc_smir; +extern crate rustc_driver; +extern crate rustc_interface; +extern crate stable_mir; + +use rustc_smir::rustc_internal; +use stable_mir::mir::mono::Instance; +use stable_mir::mir::visit::{Location, MirVisitor}; +use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind}; +use stable_mir::ty::{RigidTy, TyKind}; +use std::collections::HashSet; +use std::convert::TryFrom; +use std::io::Write; +use std::ops::ControlFlow; + +/// This function tests that we can correctly get type information from binary operations. +fn test_binops() -> ControlFlow<()> { + // Find items in the local crate. + let items = stable_mir::all_local_items(); + let mut instances = + items.into_iter().map(|item| Instance::try_from(item).unwrap()).collect::<Vec<_>>(); + while let Some(instance) = instances.pop() { + // The test below shouldn't have recursion in it. + let Some(body) = instance.body() else { + continue; + }; + let mut visitor = Visitor { locals: body.locals(), calls: Default::default() }; + visitor.visit_body(&body); + instances.extend(visitor.calls.into_iter()); + } + ControlFlow::Continue(()) +} + +struct Visitor<'a> { + locals: &'a [LocalDecl], + calls: HashSet<Instance>, +} + +impl<'a> MirVisitor for Visitor<'a> { + fn visit_statement(&mut self, stmt: &Statement, _loc: Location) { + match &stmt.kind { + StatementKind::Assign(place, Rvalue::BinaryOp(op, rhs, lhs)) => { + let ret_ty = place.ty(self.locals).unwrap(); + let op_ty = op.ty(rhs.ty(self.locals).unwrap(), lhs.ty(self.locals).unwrap()); + assert_eq!(ret_ty, op_ty, "Operation type should match the assigned place type"); + } + _ => {} + } + } + + fn visit_terminator(&mut self, term: &Terminator, _loc: Location) { + match &term.kind { + TerminatorKind::Call { func, .. } => { + let TyKind::RigidTy(RigidTy::FnDef(def, args)) = + func.ty(self.locals).unwrap().kind() + else { + return; + }; + self.calls.insert(Instance::resolve(def, &args).unwrap()); + } + _ => {} + } + } +} + +/// This test will generate and analyze a dummy crate using the stable mir. +/// For that, it will first write the dummy crate into a file. +/// Then it will create a `StableMir` using custom arguments and then +/// it will run the compiler. +fn main() { + let path = "binop_input.rs"; + generate_input(&path).unwrap(); + let args = vec!["rustc".to_string(), "--crate-type=lib".to_string(), path.to_string()]; + run!(args, test_binops).unwrap(); +} + +fn generate_input(path: &str) -> std::io::Result<()> { + let mut file = std::fs::File::create(path)?; + write!( + file, + r#" + macro_rules! binop_int {{ + ($fn:ident, $typ:ty) => {{ + pub fn $fn(lhs: $typ, rhs: $typ) {{ + let eq = lhs == rhs; + let lt = lhs < rhs; + let le = lhs <= rhs; + + let sum = lhs + rhs; + let mult = lhs * sum; + let shift = mult << 2; + let bit_or = shift | rhs; + let cmp = lhs.cmp(&bit_or); + + // Try to avoid the results above being pruned + std::hint::black_box(((eq, lt, le), cmp)); + }} + }} + }} + + binop_int!(binop_u8, u8); + binop_int!(binop_i64, i64); + + pub fn binop_bool(lhs: bool, rhs: bool) {{ + let eq = lhs == rhs; + let or = lhs | eq; + let lt = lhs < or; + let cmp = lhs.cmp(&rhs); + + // Try to avoid the results above being pruned + std::hint::black_box((lt, cmp)); + }} + + pub fn binop_char(lhs: char, rhs: char) {{ + let eq = lhs == rhs; + let lt = lhs < rhs; + let cmp = lhs.cmp(&rhs); + + // Try to avoid the results above being pruned + std::hint::black_box(([eq, lt], cmp)); + }} + + pub fn binop_ptr(lhs: *const char, rhs: *const char) {{ + let eq = lhs == rhs; + let lt = lhs < rhs; + let cmp = lhs.cmp(&rhs); + let off = unsafe {{ lhs.offset(2) }}; + + // Try to avoid the results above being pruned + std::hint::black_box(([eq, lt], cmp, off)); + }} + "# + )?; + Ok(()) +} diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs index 6da1b89ed67..4a98d37aca0 100644 --- a/tests/ui/asm/inline-syntax.rs +++ b/tests/ui/asm/inline-syntax.rs @@ -16,7 +16,7 @@ #![feature(no_core, lang_items, rustc_attrs)] #![crate_type = "rlib"] #![no_core] -#![cfg_attr(x86_64_allowed, allow(bad_asm_style))] + #[rustc_builtin_macro] macro_rules! asm { diff --git a/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs new file mode 100644 index 00000000000..a43906d01e5 --- /dev/null +++ b/tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs @@ -0,0 +1,27 @@ +//@ edition: 2021 +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#![feature(async_closure)] + +fn constrain<T: async FnOnce()>(t: T) -> T { + t +} + +fn call_once<T>(f: impl FnOnce() -> T) -> T { + f() +} + +async fn async_call_once<T>(f: impl async FnOnce() -> T) -> T { + f().await +} + +fn main() { + let c = constrain(async || {}); + call_once(c); + + let c = constrain(async || {}); + async_call_once(c); +} diff --git a/tests/ui/async-await/async-closures/mut-ref-reborrow.rs b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs new file mode 100644 index 00000000000..9f2cbd7ce1c --- /dev/null +++ b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs @@ -0,0 +1,27 @@ +//@ aux-build:block-on.rs +//@ run-pass +//@ check-run-results +//@ revisions: e2021 e2018 +//@[e2018] edition:2018 +//@[e2021] edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +async fn call_once(f: impl async FnOnce()) { f().await; } + +pub async fn async_closure(x: &mut i32) { + let c = async move || { + *x += 1; + }; + call_once(c).await; +} + +fn main() { + block_on::block_on(async { + let mut x = 0; + async_closure(&mut x).await; + assert_eq!(x, 1); + }); +} diff --git a/tests/ui/async-await/async-closures/overlapping-projs.rs b/tests/ui/async-await/async-closures/overlapping-projs.rs new file mode 100644 index 00000000000..6dd00b16103 --- /dev/null +++ b/tests/ui/async-await/async-closures/overlapping-projs.rs @@ -0,0 +1,27 @@ +//@ aux-build:block-on.rs +//@ edition:2021 +//@ run-pass +//@ check-run-results + +#![feature(async_closure)] + +extern crate block_on; + +async fn call_once(f: impl async FnOnce()) { + f().await; +} + +async fn async_main() { + let x = &mut 0; + let y = &mut 0; + let c = async || { + *x = 1; + *y = 2; + }; + call_once(c).await; + println!("{x} {y}"); +} + +fn main() { + block_on::block_on(async_main()); +} diff --git a/tests/ui/async-await/async-closures/overlapping-projs.run.stdout b/tests/ui/async-await/async-closures/overlapping-projs.run.stdout new file mode 100644 index 00000000000..8d04f961a03 --- /dev/null +++ b/tests/ui/async-await/async-closures/overlapping-projs.run.stdout @@ -0,0 +1 @@ +1 2 diff --git a/tests/ui/async-await/async-closures/precise-captures.call.run.stdout b/tests/ui/async-await/async-closures/precise-captures.call.run.stdout new file mode 100644 index 00000000000..6062556837c --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.call.run.stdout @@ -0,0 +1,29 @@ +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +after await +fixed +untouched + +after call +drop first +after await +uncaptured + +after call +drop first +after await +uncaptured diff --git a/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout b/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout new file mode 100644 index 00000000000..ddb02d47600 --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.call_once.run.stdout @@ -0,0 +1,29 @@ +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +fixed +after await +uncaptured + +after call +after await +fixed +untouched + +after call +drop first +after await +uncaptured + +after call +drop first +after await +uncaptured diff --git a/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout b/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout new file mode 100644 index 00000000000..ddb02d47600 --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.force_once.run.stdout @@ -0,0 +1,29 @@ +after call +after await +fixed +uncaptured + +after call +after await +fixed +uncaptured + +after call +fixed +after await +uncaptured + +after call +after await +fixed +untouched + +after call +drop first +after await +uncaptured + +after call +drop first +after await +uncaptured diff --git a/tests/ui/async-await/async-closures/precise-captures.rs b/tests/ui/async-await/async-closures/precise-captures.rs new file mode 100644 index 00000000000..e82dd1dbaf0 --- /dev/null +++ b/tests/ui/async-await/async-closures/precise-captures.rs @@ -0,0 +1,157 @@ +//@ aux-build:block-on.rs +//@ edition:2021 +//@ run-pass +//@ check-run-results +//@ revisions: call call_once force_once + +// call - Call the closure regularly. +// call_once - Call the closure w/ `async FnOnce`, so exercising the by_move shim. +// force_once - Force the closure mode to `FnOnce`, so exercising what was fixed +// in <https://github.com/rust-lang/rust/pull/123350>. + +#![feature(async_closure)] +#![allow(unused_mut)] + +extern crate block_on; + +#[cfg(any(call, force_once))] +macro_rules! call { + ($c:expr) => { ($c)() } +} + +#[cfg(call_once)] +async fn call_once(f: impl async FnOnce()) { + f().await +} + +#[cfg(call_once)] +macro_rules! call { + ($c:expr) => { call_once($c) } +} + +#[cfg(not(force_once))] +macro_rules! guidance { + ($c:expr) => { $c } +} + +#[cfg(force_once)] +fn infer_fnonce(c: impl async FnOnce()) -> impl async FnOnce() { c } + +#[cfg(force_once)] +macro_rules! guidance { + ($c:expr) => { infer_fnonce($c) } +} + +#[derive(Debug)] +struct Drop(&'static str); + +impl std::ops::Drop for Drop { + fn drop(&mut self) { + println!("{}", self.0); + } +} + +struct S { + a: i32, + b: Drop, + c: Drop, +} + +async fn async_main() { + // Precise capture struct + { + let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture &mut struct + { + let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct by move + { + let mut s = S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async move || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture &mut struct by move + { + let s = &mut S { a: 1, b: Drop("fix me up"), c: Drop("untouched") }; + let mut c = guidance!(async move || { + s.a = 2; + let w = &mut s.b; + w.0 = "fixed"; + }); + // `s` is still captured fully as `&mut S`. + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct, consume field + { + let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") }; + let c = guidance!(async move || { + // s.a = 2; // FIXME(async_closures): Figure out why this fails + drop(s.b); + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } + println!(); + + // Precise capture struct by move, consume field + { + let mut s = S { a: 1, b: Drop("drop first"), c: Drop("untouched") }; + let c = guidance!(async move || { + // s.a = 2; // FIXME(async_closures): Figure out why this fails + drop(s.b); + }); + s.c.0 = "uncaptured"; + let fut = call!(c); + println!("after call"); + fut.await; + println!("after await"); + } +} + +fn main() { + block_on::block_on(async_main()); +} diff --git a/tests/ui/async-await/async-closures/truncated-fields-when-imm.rs b/tests/ui/async-await/async-closures/truncated-fields-when-imm.rs new file mode 100644 index 00000000000..5c718638d80 --- /dev/null +++ b/tests/ui/async-await/async-closures/truncated-fields-when-imm.rs @@ -0,0 +1,17 @@ +//@ edition: 2021 +//@ check-pass + +#![feature(async_closure)] + +pub struct Struct { + pub path: String, +} + +// In `upvar.rs`, `truncate_capture_for_optimization` means that we don't actually +// capture `&(*s.path)` here, but instead just `&(*s)`, but ONLY when the upvar is +// immutable. This means that the assumption we have in `ByMoveBody` pass is wrong. +pub fn test(s: &Struct) { + let c = async move || { let path = &s.path; }; +} + +fn main() {} diff --git a/tests/ui/cfg/cfg-attr-cfg.rs b/tests/ui/cfg/cfg-attr-cfg.rs index 5b49966d544..67d97e760d7 100644 --- a/tests/ui/cfg/cfg-attr-cfg.rs +++ b/tests/ui/cfg/cfg-attr-cfg.rs @@ -4,5 +4,5 @@ //@ pretty-expanded FIXME #23616 -#[cfg_attr(foo, cfg(bar))] +#[cfg_attr(FALSE, cfg(bar))] fn main() { } diff --git a/tests/ui/cfg/cfg-attr-crate.rs b/tests/ui/cfg/cfg-attr-crate.rs index 7868b006e27..444704d132a 100644 --- a/tests/ui/cfg/cfg-attr-crate.rs +++ b/tests/ui/cfg/cfg-attr-crate.rs @@ -3,6 +3,6 @@ //@ pretty-expanded FIXME #23616 -#![cfg_attr(not_used, no_core)] +#![cfg_attr(FALSE, no_core)] fn main() { } diff --git a/tests/ui/cfg/cfg-macros-notfoo.rs b/tests/ui/cfg/cfg-macros-notfoo.rs index c47f4332aa3..9feb06be73e 100644 --- a/tests/ui/cfg/cfg-macros-notfoo.rs +++ b/tests/ui/cfg/cfg-macros-notfoo.rs @@ -1,11 +1,9 @@ //@ run-pass -//@ compile-flags: // check that cfg correctly chooses between the macro impls (see also // cfg-macros-foo.rs) - -#[cfg(foo)] +#[cfg(FALSE)] #[macro_use] mod foo { macro_rules! bar { @@ -13,7 +11,7 @@ mod foo { } } -#[cfg(not(foo))] +#[cfg(not(FALSE))] #[macro_use] mod foo { macro_rules! bar { diff --git a/tests/ui/cfg/cfg-match-arm.rs b/tests/ui/cfg/cfg-match-arm.rs index a41337a19a3..e646a63b8fb 100644 --- a/tests/ui/cfg/cfg-match-arm.rs +++ b/tests/ui/cfg/cfg-match-arm.rs @@ -10,9 +10,9 @@ enum Foo { fn foo(f: Foo) { match f { Foo::Bar => {}, - #[cfg(not(asdfa))] + #[cfg(not(FALSE))] Foo::Baz => {}, - #[cfg(afsd)] + #[cfg(FALSE)] Basdfwe => {} } } diff --git a/tests/ui/cfg/cfg-panic-abort.rs b/tests/ui/cfg/cfg-panic-abort.rs index 49adfd55c68..448fde21086 100644 --- a/tests/ui/cfg/cfg-panic-abort.rs +++ b/tests/ui/cfg/cfg-panic-abort.rs @@ -2,15 +2,11 @@ //@ compile-flags: -C panic=abort //@ no-prefer-dynamic - #[cfg(panic = "unwind")] pub fn bad() -> i32 { } #[cfg(not(panic = "abort"))] pub fn bad() -> i32 { } -#[cfg(panic = "some_imaginary_future_panic_handler")] -pub fn bad() -> i32 { } - #[cfg(panic = "abort")] pub fn main() { } diff --git a/tests/ui/cfg/cfg-panic.rs b/tests/ui/cfg/cfg-panic.rs index 0f1f539ebe3..4e3ed0cd9c2 100644 --- a/tests/ui/cfg/cfg-panic.rs +++ b/tests/ui/cfg/cfg-panic.rs @@ -2,15 +2,11 @@ //@ compile-flags: -C panic=unwind //@ needs-unwind - #[cfg(panic = "abort")] pub fn bad() -> i32 { } #[cfg(not(panic = "unwind"))] pub fn bad() -> i32 { } -#[cfg(panic = "some_imaginary_future_panic_handler")] -pub fn bad() -> i32 { } - #[cfg(panic = "unwind")] pub fn main() { } diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs index 6de5eb5c4c6..9245f6d9757 100644 --- a/tests/ui/cfg/cfg_stmt_expr.rs +++ b/tests/ui/cfg/cfg_stmt_expr.rs @@ -7,49 +7,49 @@ fn main() { let a = 413; - #[cfg(unset)] + #[cfg(FALSE)] let a = (); assert_eq!(a, 413); let mut b = 612; - #[cfg(unset)] + #[cfg(FALSE)] { b = 1111; } assert_eq!(b, 612); - #[cfg(unset)] + #[cfg(FALSE)] undefined_fn(); - #[cfg(unset)] + #[cfg(FALSE)] undefined_macro!(); - #[cfg(unset)] + #[cfg(FALSE)] undefined_macro![]; - #[cfg(unset)] + #[cfg(FALSE)] undefined_macro!{}; // pretty printer bug... - // #[cfg(unset)] + // #[cfg(FALSE)] // undefined_macro!{} - let () = (#[cfg(unset)] 341,); // Should this also work on parens? - let t = (1, #[cfg(unset)] 3, 4); + let () = (#[cfg(FALSE)] 341,); // Should this also work on parens? + let t = (1, #[cfg(FALSE)] 3, 4); assert_eq!(t, (1, 4)); let f = |_: u32, _: u32| (); - f(2, 1, #[cfg(unset)] 6); + f(2, 1, #[cfg(FALSE)] 6); - let _: u32 = a.clone(#[cfg(unset)] undefined); + let _: u32 = a.clone(#[cfg(FALSE)] undefined); - let _: [(); 0] = [#[cfg(unset)] 126]; - let t = [#[cfg(unset)] 1, 2, 6]; + let _: [(); 0] = [#[cfg(FALSE)] 126]; + let t = [#[cfg(FALSE)] 1, 2, 6]; assert_eq!(t, [2, 6]); { let r; - #[cfg(unset)] + #[cfg(FALSE)] (r = 5); - #[cfg(not(unset))] + #[cfg(not(FALSE))] (r = 10); assert_eq!(r, 10); } @@ -69,13 +69,13 @@ fn main() { } } - let n = if_cfg!(unset? { + let n = if_cfg!(FALSE? { 413 } else { 612 }); - assert_eq!((#[cfg(unset)] 1, #[cfg(not(unset))] 2), (2,)); + assert_eq!((#[cfg(FALSE)] 1, #[cfg(not(FALSE))] 2), (2,)); assert_eq!(n, 612); // check that lints work diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs index f39663adda2..a4f334dd696 100644 --- a/tests/ui/cfg/conditional-compile.rs +++ b/tests/ui/cfg/conditional-compile.rs @@ -6,31 +6,31 @@ // Crate use statements -#[cfg(bogus)] +#[cfg(FALSE)] use flippity; -#[cfg(bogus)] +#[cfg(FALSE)] static b: bool = false; static b: bool = true; mod rustrt { - #[cfg(bogus)] + #[cfg(FALSE)] extern "C" { // This symbol doesn't exist and would be a link error if this // module was codegened - pub fn bogus(); + pub fn FALSE(); } extern "C" {} } -#[cfg(bogus)] +#[cfg(FALSE)] type t = isize; type t = bool; -#[cfg(bogus)] +#[cfg(FALSE)] enum tg { foo, } @@ -39,12 +39,12 @@ enum tg { bar, } -#[cfg(bogus)] +#[cfg(FALSE)] struct r { i: isize, } -#[cfg(bogus)] +#[cfg(FALSE)] fn r(i: isize) -> r { r { i: i } } @@ -57,11 +57,11 @@ fn r(i: isize) -> r { r { i: i } } -#[cfg(bogus)] +#[cfg(FALSE)] mod m { // This needs to parse but would fail in typeck. Since it's not in // the current config it should not be typechecked. - pub fn bogus() { + pub fn FALSE() { return 0; } } @@ -69,22 +69,22 @@ mod m { mod m { // Submodules have slightly different code paths than the top-level // module, so let's make sure this jazz works here as well - #[cfg(bogus)] + #[cfg(FALSE)] pub fn f() {} pub fn f() {} } -// Since the bogus configuration isn't defined main will just be +// Since the FALSE configuration isn't defined main will just be // parsed, but nothing further will be done with it -#[cfg(bogus)] +#[cfg(FALSE)] pub fn main() { panic!() } pub fn main() { // Exercise some of the configured items in ways that wouldn't be possible - // if they had the bogus definition + // if they had the FALSE definition assert!((b)); let _x: t = true; let _y: tg = tg::bar; @@ -93,14 +93,14 @@ pub fn main() { } fn test_in_fn_ctxt() { - #[cfg(bogus)] + #[cfg(FALSE)] fn f() { panic!() } fn f() {} f(); - #[cfg(bogus)] + #[cfg(FALSE)] static i: isize = 0; static i: isize = 1; assert_eq!(i, 1); @@ -109,7 +109,7 @@ fn test_in_fn_ctxt() { mod test_foreign_items { pub mod rustrt { extern "C" { - #[cfg(bogus)] + #[cfg(FALSE)] pub fn write() -> String; pub fn write() -> String; } @@ -117,7 +117,7 @@ mod test_foreign_items { } mod test_use_statements { - #[cfg(bogus)] + #[cfg(FALSE)] use flippity_foo; } @@ -127,24 +127,24 @@ mod test_methods { } impl Fooable for Foo { - #[cfg(bogus)] + #[cfg(FALSE)] fn what(&self) {} fn what(&self) {} - #[cfg(bogus)] + #[cfg(FALSE)] fn the(&self) {} fn the(&self) {} } trait Fooable { - #[cfg(bogus)] + #[cfg(FALSE)] fn what(&self); fn what(&self); - #[cfg(bogus)] + #[cfg(FALSE)] fn the(&self); fn the(&self); diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs index b9548e91183..9b3208cb87c 100644 --- a/tests/ui/cfg/diagnostics-reexport.rs +++ b/tests/ui/cfg/diagnostics-reexport.rs @@ -14,7 +14,7 @@ pub use a::x; //~| NOTE no `x` in `a` mod a { - #[cfg(no)] + #[cfg(FALSE)] pub fn x() {} //~^ NOTE found an item that was configured out } @@ -25,10 +25,10 @@ pub use b::{x, y}; //~| NOTE no `y` in `b` mod b { - #[cfg(no)] + #[cfg(FALSE)] pub fn x() {} //~^ NOTE found an item that was configured out - #[cfg(no)] + #[cfg(FALSE)] pub fn y() {} //~^ NOTE found an item that was configured out } diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index 011ef6e101d..493132d462a 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `FALSE` LL | #[cfg(FALSE)] | ^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(FALSE)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr index d6c377e21ad..09a1c950267 100644 --- a/tests/ui/check-cfg/cargo-feature.none.stderr +++ b/tests/ui/check-cfg/cargo-feature.none.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: consider using a Cargo feature instead or adding `println!("cargo:rustc-check-cfg=cfg(tokio_unstable)");` to the top of a `build.rs` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr index 11dfd4fa4b6..4db9c66fc86 100644 --- a/tests/ui/check-cfg/cargo-feature.some.stderr +++ b/tests/ui/check-cfg/cargo-feature.some.stderr @@ -25,7 +25,7 @@ warning: unexpected `cfg` condition name: `tokio_unstable` LL | #[cfg(tokio_unstable)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: consider using a Cargo feature instead or adding `println!("cargo:rustc-check-cfg=cfg(tokio_unstable)");` to the top of a `build.rs` = note: see <https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr index 7d374fc81d3..9c190117e74 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `value` LL | #[cfg(value)] | ^^^^^ | - = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(value)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr index 13e6891c353..7113790b83a 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `my_value` LL | #[cfg(my_value)] | ^^^^^^^^ | - = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(my_value)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr index a2f9ccfec05..ba9f5f4acbd 100644 --- a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr +++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `linux` LL | #[cfg(linux)] | ^^^^^ help: found config with similar value: `target_os = "linux"` | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(linux)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index 37637e3b153..446b8f408e3 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `target_architecture` LL | #[cfg(target(os = "linux", architecture = "arm"))] | ^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr index 4f770e91c58..d2870263342 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr index c7eaf435f75..b24b10bb615 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr index c7eaf435f75..b24b10bb615 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/exhaustive-names.stderr b/tests/ui/check-cfg/exhaustive-names.stderr index 3ed5c77e2a4..6ca7ed93625 100644 --- a/tests/ui/check-cfg/exhaustive-names.stderr +++ b/tests/ui/check-cfg/exhaustive-names.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `unknown_key` LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 007f9de0331..87fabf8245f 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -44,7 +44,7 @@ warning: unexpected `cfg` condition name: `uu` LL | #[cfg_attr(uu, test)] | ^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(uu)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr index f2660e4775b..1afdbe84d34 100644 --- a/tests/ui/check-cfg/stmt-no-ice.stderr +++ b/tests/ui/check-cfg/stmt-no-ice.stderr @@ -4,7 +4,7 @@ warning: unexpected `cfg` condition name: `crossbeam_loom` LL | #[cfg(crossbeam_loom)] | ^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(crossbeam_loom)` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr index a0386403e25..467f9675f7f 100644 --- a/tests/ui/check-cfg/well-known-names.stderr +++ b/tests/ui/check-cfg/well-known-names.stderr @@ -18,7 +18,7 @@ warning: unexpected `cfg` condition name: `features` LL | #[cfg(features = "foo")] | ^^^^^^^^^^^^^^^^ | - = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` + = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows` = help: to expect this configuration use `--check-cfg=cfg(features, values("foo"))` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration diff --git a/tests/ui/check-cfg/well-known-values.rs b/tests/ui/check-cfg/well-known-values.rs index fa062a3fe2e..2758a793538 100644 --- a/tests/ui/check-cfg/well-known-values.rs +++ b/tests/ui/check-cfg/well-known-values.rs @@ -14,6 +14,7 @@ #![feature(cfg_target_has_atomic)] #![feature(cfg_target_has_atomic_equal_alignment)] #![feature(cfg_target_thread_local)] +#![feature(cfg_ub_checks)] // This part makes sure that none of the well known names are // unexpected. @@ -71,6 +72,8 @@ //~^ WARN unexpected `cfg` condition value test = "_UNEXPECTED_VALUE", //~^ WARN unexpected `cfg` condition value + ub_checks = "_UNEXPECTED_VALUE", + //~^ WARN unexpected `cfg` condition value unix = "_UNEXPECTED_VALUE", //~^ WARN unexpected `cfg` condition value windows = "_UNEXPECTED_VALUE", diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 31553371101..729794150f6 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -1,5 +1,5 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:26:5 + --> $DIR/well-known-values.rs:27:5 | LL | clippy = "_UNEXPECTED_VALUE", | ^^^^^^---------------------- @@ -11,7 +11,7 @@ LL | clippy = "_UNEXPECTED_VALUE", = note: `#[warn(unexpected_cfgs)]` on by default warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:28:5 + --> $DIR/well-known-values.rs:29:5 | LL | debug_assertions = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^---------------------- @@ -22,7 +22,7 @@ LL | debug_assertions = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:30:5 + --> $DIR/well-known-values.rs:31:5 | LL | doc = "_UNEXPECTED_VALUE", | ^^^---------------------- @@ -33,7 +33,7 @@ LL | doc = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:32:5 + --> $DIR/well-known-values.rs:33:5 | LL | doctest = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -44,7 +44,7 @@ LL | doctest = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:34:5 + --> $DIR/well-known-values.rs:35:5 | LL | miri = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -55,7 +55,7 @@ LL | miri = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:36:5 + --> $DIR/well-known-values.rs:37:5 | LL | overflow_checks = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^---------------------- @@ -66,7 +66,7 @@ LL | overflow_checks = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:38:5 + --> $DIR/well-known-values.rs:39:5 | LL | panic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +75,7 @@ LL | panic = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:40:5 + --> $DIR/well-known-values.rs:41:5 | LL | proc_macro = "_UNEXPECTED_VALUE", | ^^^^^^^^^^---------------------- @@ -86,7 +86,7 @@ LL | proc_macro = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:42:5 + --> $DIR/well-known-values.rs:43:5 | LL | relocation_model = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -95,7 +95,7 @@ LL | relocation_model = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:44:5 + --> $DIR/well-known-values.rs:45:5 | LL | sanitize = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -104,7 +104,7 @@ LL | sanitize = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:46:5 + --> $DIR/well-known-values.rs:47:5 | LL | target_abi = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -113,7 +113,7 @@ LL | target_abi = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:48:5 + --> $DIR/well-known-values.rs:49:5 | LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -122,7 +122,7 @@ LL | target_arch = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:50:5 + --> $DIR/well-known-values.rs:51:5 | LL | target_endian = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -131,7 +131,7 @@ LL | target_endian = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:52:5 + --> $DIR/well-known-values.rs:53:5 | LL | target_env = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -140,7 +140,7 @@ LL | target_env = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:54:5 + --> $DIR/well-known-values.rs:55:5 | LL | target_family = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -149,7 +149,7 @@ LL | target_family = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:56:5 + --> $DIR/well-known-values.rs:57:5 | LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -158,7 +158,7 @@ LL | target_feature = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:58:5 + --> $DIR/well-known-values.rs:59:5 | LL | target_has_atomic = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -167,7 +167,7 @@ LL | target_has_atomic = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:60:5 + --> $DIR/well-known-values.rs:61:5 | LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -176,7 +176,7 @@ LL | target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:62:5 + --> $DIR/well-known-values.rs:63:5 | LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,7 +185,7 @@ LL | target_has_atomic_load_store = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:64:5 + --> $DIR/well-known-values.rs:65:5 | LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -194,7 +194,7 @@ LL | target_os = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:66:5 + --> $DIR/well-known-values.rs:67:5 | LL | target_pointer_width = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -203,7 +203,7 @@ LL | target_pointer_width = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:68:5 + --> $DIR/well-known-values.rs:69:5 | LL | target_thread_local = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^---------------------- @@ -214,7 +214,7 @@ LL | target_thread_local = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:70:5 + --> $DIR/well-known-values.rs:71:5 | LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +223,7 @@ LL | target_vendor = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:72:5 + --> $DIR/well-known-values.rs:73:5 | LL | test = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -234,7 +234,18 @@ LL | test = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:74:5 + --> $DIR/well-known-values.rs:75:5 + | +LL | ub_checks = "_UNEXPECTED_VALUE", + | ^^^^^^^^^---------------------- + | | + | help: remove the value + | + = note: no expected value for `ub_checks` + = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration + +warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` + --> $DIR/well-known-values.rs:77:5 | LL | unix = "_UNEXPECTED_VALUE", | ^^^^---------------------- @@ -245,7 +256,7 @@ LL | unix = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` - --> $DIR/well-known-values.rs:76:5 + --> $DIR/well-known-values.rs:79:5 | LL | windows = "_UNEXPECTED_VALUE", | ^^^^^^^---------------------- @@ -256,7 +267,7 @@ LL | windows = "_UNEXPECTED_VALUE", = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `linuz` - --> $DIR/well-known-values.rs:82:7 + --> $DIR/well-known-values.rs:85:7 | LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | ^^^^^^^^^^^^------- @@ -266,5 +277,5 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm` = note: see <https://doc.rust-lang.org/nightly/unstable-book/compiler-flags/check-cfg.html> for more information about checking conditional configuration -warning: 27 warnings emitted +warning: 28 warnings emitted diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed new file mode 100644 index 00000000000..0fa6ac1dd99 --- /dev/null +++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.fixed @@ -0,0 +1,9 @@ +// Check that revisioned `run-rustfix` does not fail with issues related to `.` in crate name. +//@ revisions: foo +//@[foo] run-rustfix +#![deny(unused_variables)] + +fn main() { + let _x = 0usize; + //~^ ERROR unused variable: `x` +} diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr new file mode 100644 index 00000000000..74384ef24af --- /dev/null +++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.foo.stderr @@ -0,0 +1,14 @@ +error: unused variable: `x` + --> $DIR/run-rustfix-revisions.rs:7:9 + | +LL | let x = 0usize; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/run-rustfix-revisions.rs:4:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/compiletest-self-test/run-rustfix-revisions.rs b/tests/ui/compiletest-self-test/run-rustfix-revisions.rs new file mode 100644 index 00000000000..84c5b7a2d0a --- /dev/null +++ b/tests/ui/compiletest-self-test/run-rustfix-revisions.rs @@ -0,0 +1,9 @@ +// Check that revisioned `run-rustfix` does not fail with issues related to `.` in crate name. +//@ revisions: foo +//@[foo] run-rustfix +#![deny(unused_variables)] + +fn main() { + let x = 0usize; + //~^ ERROR unused variable: `x` +} diff --git a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs index 72b0db5da84..bca29f0da2b 100644 --- a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs +++ b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.rs @@ -1,13 +1,11 @@ // Check that `#[cfg_attr($PREDICATE,)]` triggers the `unused_attribute` lint. -//@ compile-flags: --cfg TRUE - #![deny(unused)] #[cfg_attr(FALSE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes fn _f() {} -#[cfg_attr(TRUE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes +#[cfg_attr(not(FALSE),)] //~ ERROR `#[cfg_attr]` does not expand to any attributes fn _g() {} fn main() {} diff --git a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr index 87b69881353..a858afe2f2b 100644 --- a/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr +++ b/tests/ui/conditional-compilation/cfg-attr-empty-is-unused.stderr @@ -1,21 +1,21 @@ error: `#[cfg_attr]` does not expand to any attributes - --> $DIR/cfg-attr-empty-is-unused.rs:7:1 + --> $DIR/cfg-attr-empty-is-unused.rs:5:1 | LL | #[cfg_attr(FALSE,)] | ^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here - --> $DIR/cfg-attr-empty-is-unused.rs:5:9 + --> $DIR/cfg-attr-empty-is-unused.rs:3:9 | LL | #![deny(unused)] | ^^^^^^ = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` error: `#[cfg_attr]` does not expand to any attributes - --> $DIR/cfg-attr-empty-is-unused.rs:10:1 + --> $DIR/cfg-attr-empty-is-unused.rs:8:1 | -LL | #[cfg_attr(TRUE,)] - | ^^^^^^^^^^^^^^^^^^ +LL | #[cfg_attr(not(FALSE),)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.rs b/tests/ui/conditional-compilation/cfg-in-crate-1.rs index 59be27a065e..ecd3722bf4c 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.rs +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.rs @@ -1,3 +1,3 @@ //@ error-pattern: `main` function not found -#![cfg(bar)] +#![cfg(FALSE)] diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr index 98be6d01f1b..6067a3a921c 100644 --- a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr +++ b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr @@ -1,8 +1,8 @@ error[E0601]: `main` function not found in crate `cfg_in_crate_1` - --> $DIR/cfg-in-crate-1.rs:3:13 + --> $DIR/cfg-in-crate-1.rs:3:15 | -LL | #![cfg(bar)] - | ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` +LL | #![cfg(FALSE)] + | ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs` error: aborting due to 1 previous error diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs index 0ddbd8a156d..ae85f38e645 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs @@ -2,10 +2,10 @@ #![feature(custom_test_frameworks)] fn main() { - let _ = #[cfg(unset)] (); + let _ = #[cfg(FALSE)] (); //~^ ERROR removing an expression is not supported in this position - let _ = 1 + 2 + #[cfg(unset)] 3; + let _ = 1 + 2 + #[cfg(FALSE)] 3; //~^ ERROR removing an expression is not supported in this position - let _ = [1, 2, 3][#[cfg(unset)] 1]; + let _ = [1, 2, 3][#[cfg(FALSE)] 1]; //~^ ERROR removing an expression is not supported in this position } diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr index 933b7dc184a..06eaa59efdd 100644 --- a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr +++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr @@ -1,19 +1,19 @@ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:5:13 | -LL | let _ = #[cfg(unset)] (); +LL | let _ = #[cfg(FALSE)] (); | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:7:21 | -LL | let _ = 1 + 2 + #[cfg(unset)] 3; +LL | let _ = 1 + 2 + #[cfg(FALSE)] 3; | ^^^^^^^^^^^^^ error: removing an expression is not supported in this position --> $DIR/cfg-non-opt-expr.rs:9:23 | -LL | let _ = [1, 2, 3][#[cfg(unset)] 1]; +LL | let _ = [1, 2, 3][#[cfg(FALSE)] 1]; | ^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs new file mode 100644 index 00000000000..dd0b1e8c9f7 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.rs @@ -0,0 +1,15 @@ +// ICE unknown alias DefKind: AnonConst +// issue: rust-lang/rust#116710 +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +struct A<const N: u32 = 1, const M: u32 = u8>; +//~^ ERROR expected value, found builtin type `u8` + +trait Trait {} +impl<const N: u32> Trait for A<N> {} + +impl<const N: u32> Trait for A<N> {} +//~^ ERROR conflicting implementations of trait `Trait` for type `A<_>` + +pub fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr new file mode 100644 index 00000000000..80ac96d4870 --- /dev/null +++ b/tests/ui/const-generics/generic_const_exprs/unknown-alias-defkind-anonconst-ice-116710.stderr @@ -0,0 +1,19 @@ +error[E0423]: expected value, found builtin type `u8` + --> $DIR/unknown-alias-defkind-anonconst-ice-116710.rs:6:43 + | +LL | struct A<const N: u32 = 1, const M: u32 = u8>; + | ^^ not a value + +error[E0119]: conflicting implementations of trait `Trait` for type `A<_>` + --> $DIR/unknown-alias-defkind-anonconst-ice-116710.rs:12:1 + | +LL | impl<const N: u32> Trait for A<N> {} + | --------------------------------- first implementation here +LL | +LL | impl<const N: u32> Trait for A<N> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A<_>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0119, E0423. +For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/consts/const-eval/const-eval-query-stack.stderr b/tests/ui/consts/const-eval/const-eval-query-stack.stderr index 96fd9ed5f04..0a28c5b80bf 100644 --- a/tests/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/tests/ui/consts/const-eval/const-eval-query-stack.stderr @@ -4,6 +4,8 @@ error: internal compiler error[E0080]: evaluation of constant value failed LL | const X: i32 = 1 / 0; | ^^^^^ attempt to divide `1_i32` by zero +note: please make sure that you have updated to the latest nightly + query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `X` #1 [eval_to_const_value_raw] simplifying constant for the type system `X` diff --git a/tests/ui/consts/do-not-ice-on-field-access-of-err-type.rs b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.rs new file mode 100644 index 00000000000..a2e336b703e --- /dev/null +++ b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.rs @@ -0,0 +1,9 @@ +trait Foo {} +impl<T> Foo for T {} + +fn main() { + let array = [(); { loop {} }]; //~ ERROR constant evaluation is taking a long time + + let tup = (7,); + let x: &dyn Foo = &tup.0; +} diff --git a/tests/ui/consts/do-not-ice-on-field-access-of-err-type.stderr b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.stderr new file mode 100644 index 00000000000..02b8904fbde --- /dev/null +++ b/tests/ui/consts/do-not-ice-on-field-access-of-err-type.stderr @@ -0,0 +1,17 @@ +error: constant evaluation is taking a long time + --> $DIR/do-not-ice-on-field-access-of-err-type.rs:5:24 + | +LL | let array = [(); { loop {} }]; + | ^^^^^^^ + | + = 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/do-not-ice-on-field-access-of-err-type.rs:5:22 + | +LL | let array = [(); { loop {} }]; + | ^^^^^^^^^^^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs b/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs new file mode 100644 index 00000000000..65da2c3f5c7 --- /dev/null +++ b/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs @@ -0,0 +1,22 @@ +//@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only + +#[no_mangle] +pub fn baz<F>(mut cb: F, data: u32) where F: FnMut(u32) { + cb(data); +} + +#[no_mangle] +pub fn bar<F>(cb: F, data: u32) where F: FnMut(u32) { + baz(cb, data); +} + +#[no_mangle] +pub fn foo<F>(cb: F, data: u32) where F: FnMut(u32) { + bar(cb, data); +} + +pub fn capture_backtrace() -> std::backtrace::Backtrace { + let mut bt = None; + foo(|_| bt = Some(std::backtrace::Backtrace::capture()), 42); + bt.unwrap() +} diff --git a/tests/ui/debuginfo/backtrace-line-tables-only.rs b/tests/ui/debuginfo/backtrace-line-tables-only.rs new file mode 100644 index 00000000000..044f59e483a --- /dev/null +++ b/tests/ui/debuginfo/backtrace-line-tables-only.rs @@ -0,0 +1,49 @@ +// Test that when debug info only includes line tables that backtrace is still generated +// successfully. +// Original test: +// <https://github.com/rust-lang/backtrace-rs/tree/6fa4b85b9962c3e1be8c2e5cc605cd078134152b/crates/line-tables-only>. +// Part of <https://github.com/rust-lang/rust/issues/122899> porting some backtrace tests to rustc. +// This test diverges from the original test in that it now uses a Rust library auxiliary because +// rustc now has `-Cdebuginfo=line-tables-only`. +// ignore-tidy-linelength +//@ run-pass +//@ compile-flags: -Cstrip=none -Cdebuginfo=line-tables-only +//@ ignore-android FIXME #17520 +//@ ignore-fuchsia Backtraces not symbolized +//@ needs-unwind +//@ aux-build: line-tables-only-helper.rs + +#![feature(backtrace_frames)] + +extern crate line_tables_only_helper; + +use std::backtrace::Backtrace; + +fn assert_contains( + backtrace: &Backtrace, + expected_name: &str, + expected_file: &str, + expected_line: u32, +) { + // FIXME(jieyouxu): fix this ugly fragile test when `BacktraceFrame` has accessors like... + // `symbols()`. + let backtrace = format!("{:#?}", backtrace); + eprintln!("{}", backtrace); + assert!(backtrace.contains(expected_name), "backtrace does not contain expected name {}", expected_name); + assert!(backtrace.contains(expected_file), "backtrace does not contain expected file {}", expected_file); + assert!(backtrace.contains(&expected_line.to_string()), "backtrace does not contain expected line {}", expected_line); +} + +fn main() { + std::env::set_var("RUST_BACKTRACE", "1"); + let backtrace = line_tables_only_helper::capture_backtrace(); + + // FIXME(jieyouxu): for some forsaken reason on i686-msvc `foo` doesn't have an entry in the + // line tables? + #[cfg(not(all(target_pointer_width = "32", target_env = "msvc")))] + { + assert_contains(&backtrace, "foo", "line-tables-only-helper.rs", 5); + } + assert_contains(&backtrace, "bar", "line-tables-only-helper.rs", 10); + assert_contains(&backtrace, "baz", "line-tables-only-helper.rs", 15); +} diff --git a/tests/ui/does-nothing.rs b/tests/ui/does-nothing.rs deleted file mode 100644 index e4992e2cfd3..00000000000 --- a/tests/ui/does-nothing.rs +++ /dev/null @@ -1,2 +0,0 @@ -fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); } -//~^ ERROR cannot find value `this_does_nothing_what_the` in this scope diff --git a/tests/ui/does-nothing.stderr b/tests/ui/does-nothing.stderr deleted file mode 100644 index d5ea3626e81..00000000000 --- a/tests/ui/does-nothing.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0425]: cannot find value `this_does_nothing_what_the` in this scope - --> $DIR/does-nothing.rs:1:32 - | -LL | fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.rs b/tests/ui/editions/edition-raw-pointer-method-2018.rs index b346953e187..ad47553d5b7 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.rs +++ b/tests/ui/editions/edition-raw-pointer-method-2018.rs @@ -6,6 +6,6 @@ fn main() { let x = 0; let y = &x as *const _; + //~^ error: type annotations needed let _ = y.is_null(); - //~^ error: cannot call a method on a raw pointer with an unknown pointee type [E0699] } diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.stderr b/tests/ui/editions/edition-raw-pointer-method-2018.stderr index 663843ad7bc..2792d1e7400 100644 --- a/tests/ui/editions/edition-raw-pointer-method-2018.stderr +++ b/tests/ui/editions/edition-raw-pointer-method-2018.stderr @@ -1,9 +1,17 @@ -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type - --> $DIR/edition-raw-pointer-method-2018.rs:9:15 +error[E0282]: type annotations needed for `*const _` + --> $DIR/edition-raw-pointer-method-2018.rs:8:9 | +LL | let y = &x as *const _; + | ^ +LL | LL | let _ = y.is_null(); - | ^^^^^^^ + | ------- cannot call a method on a raw pointer with an unknown pointee type + | +help: consider giving `y` an explicit type, where the placeholders `_` are specified + | +LL | let y: *const _ = &x as *const _; + | ++++++++++ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0699`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs index 72d83215ade..c139b347d99 100644 --- a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs +++ b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs @@ -25,7 +25,7 @@ fn bar() { let x: () = true; // Should not error due to the #[cfg(FALSE)] } - #[cfg_attr(not(unset_attr), cfg(FALSE))] + #[cfg_attr(not(FALSE), cfg(FALSE))] if true { let a: () = true; // Should not error due to the applied #[cfg(FALSE)] } diff --git a/tests/ui/feature-gates/feature-gate-cfg_ub_checks.rs b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.rs new file mode 100644 index 00000000000..c24c0066e18 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.rs @@ -0,0 +1,5 @@ +#![crate_type = "lib"] + +pub fn ub_checks_are_enabled() -> bool { + cfg!(ub_checks) //~ ERROR `cfg(ub_checks)` is experimental +} diff --git a/tests/ui/feature-gates/feature-gate-cfg_ub_checks.stderr b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.stderr new file mode 100644 index 00000000000..aa12ee1db6b --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg_ub_checks.stderr @@ -0,0 +1,13 @@ +error[E0658]: `cfg(ub_checks)` is experimental and subject to change + --> $DIR/feature-gate-cfg_ub_checks.rs:4:10 + | +LL | cfg!(ub_checks) + | ^^^^^^^^^ + | + = note: see issue #123499 <https://github.com/rust-lang/rust/issues/123499> for more information + = help: add `#![feature(cfg_ub_checks)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs b/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs deleted file mode 100644 index c537fc419f6..00000000000 --- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.rs +++ /dev/null @@ -1,4 +0,0 @@ -//@ check-pass - -#![warn(unnameable_types)] //~ WARN unknown lint -fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr b/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr deleted file mode 100644 index 72ac3792fff..00000000000 --- a/tests/ui/feature-gates/feature-gate-type_privacy_lints.stderr +++ /dev/null @@ -1,14 +0,0 @@ -warning: unknown lint: `unnameable_types` - --> $DIR/feature-gate-type_privacy_lints.rs:3:1 - | -LL | #![warn(unnameable_types)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: the `unnameable_types` lint is unstable - = note: see issue #48054 <https://github.com/rust-lang/rust/issues/48054> for more information - = help: add `#![feature(type_privacy_lints)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - = note: `#[warn(unknown_lints)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/filter-block-view-items.rs index edb9ce38006..f582c51a3a6 100644 --- a/tests/ui/filter-block-view-items.rs +++ b/tests/ui/filter-block-view-items.rs @@ -4,5 +4,5 @@ pub fn main() { // Make sure that this view item is filtered out because otherwise it would // trigger a compilation error - #[cfg(not_present)] use bar as foo; + #[cfg(FALSE)] use bar as foo; } diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs index a3f3b1a6d4d..e06341ddf31 100644 --- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs +++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.rs @@ -1,8 +1,7 @@ -#![warn(unused_lifetimes)] +#![warn(unused_lifetimes, redundant_lifetimes)] pub trait X { - type Y<'a: 'static>; - //~^ WARNING unnecessary lifetime parameter + type Y<'a: 'static>; //~ WARN unnecessary lifetime parameter `'a` } impl X for () { diff --git a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr index 8d21b9172c8..4f41ec025fc 100644 --- a/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr +++ b/tests/ui/generic-associated-types/unsatisfied-item-lifetime-bound.stderr @@ -1,18 +1,5 @@ -warning: unnecessary lifetime parameter `'a` - --> $DIR/unsatisfied-item-lifetime-bound.rs:4:12 - | -LL | type Y<'a: 'static>; - | ^^ - | - = help: you can use the `'static` lifetime directly, in place of `'a` -note: the lint level is defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:1:9 - | -LL | #![warn(unused_lifetimes)] - | ^^^^^^^^^^^^^^^^ - error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:9:18 + --> $DIR/unsatisfied-item-lifetime-bound.rs:8:18 | LL | type Y<'a: 'static>; | ------------------- definition of `Y` from trait @@ -21,7 +8,7 @@ LL | type Y<'a> = &'a (); | ^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:9:12 + --> $DIR/unsatisfied-item-lifetime-bound.rs:8:12 | LL | type Y<'a> = &'a (); | ^^ @@ -32,44 +19,57 @@ LL | type Y<'a> = &'a () where 'a: 'static; | +++++++++++++++++ error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:14:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:13:8 | LL | f: <T as X>::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:13:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:12:10 | LL | struct B<'a, T: for<'r> X<Y<'r> = &'r ()>> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:19:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:18:8 | LL | f: <T as X>::Y<'a>, | ^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:18:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:17:10 | LL | struct C<'a, T: X> { | ^^ = note: but lifetime parameter must outlive the static lifetime error[E0478]: lifetime bound not satisfied - --> $DIR/unsatisfied-item-lifetime-bound.rs:24:8 + --> $DIR/unsatisfied-item-lifetime-bound.rs:23:8 | LL | f: <() as X>::Y<'a>, | ^^^^^^^^^^^^^^^^ | note: lifetime parameter instantiated with the lifetime `'a` as defined here - --> $DIR/unsatisfied-item-lifetime-bound.rs:23:10 + --> $DIR/unsatisfied-item-lifetime-bound.rs:22:10 | LL | struct D<'a> { | ^^ = note: but lifetime parameter must outlive the static lifetime +warning: unnecessary lifetime parameter `'a` + --> $DIR/unsatisfied-item-lifetime-bound.rs:4:12 + | +LL | type Y<'a: 'static>; + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` +note: the lint level is defined here + --> $DIR/unsatisfied-item-lifetime-bound.rs:1:27 + | +LL | #![warn(unused_lifetimes, redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ + error: aborting due to 4 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0478`. diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs new file mode 100644 index 00000000000..2607013ec63 --- /dev/null +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.rs @@ -0,0 +1,19 @@ +// ICE: assertion failed: !value.has_infer() +// issue: rust-lang/rust#115806 +#![feature(associated_const_equality)] +#![allow(incomplete_features)] + +pub struct NoPin; + +impl<TA> Pins<TA> for NoPin {} + +pub trait PinA<PER> { + const A: &'static () = &(); +} + +pub trait Pins<USART> {} + +impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {} +//~^ ERROR conflicting implementations of trait `Pins<_>` for type `NoPin` + +pub fn main() {} diff --git a/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr new file mode 100644 index 00000000000..9a9baaddcba --- /dev/null +++ b/tests/ui/generic-const-items/assoc-const-no-infer-ice-115806.stderr @@ -0,0 +1,14 @@ +error[E0119]: conflicting implementations of trait `Pins<_>` for type `NoPin` + --> $DIR/assoc-const-no-infer-ice-115806.rs:16:1 + | +LL | impl<TA> Pins<TA> for NoPin {} + | --------------------------- first implementation here +... +LL | impl<USART, T> Pins<USART> for T where T: PinA<USART, A = { &() }> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `NoPin` + | + = note: downstream crates may implement trait `PinA<_>` for type `NoPin` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0119`. diff --git a/tests/ui/impl-trait/different_where_bounds.rs b/tests/ui/impl-trait/different_where_bounds.rs new file mode 100644 index 00000000000..87ae6db2822 --- /dev/null +++ b/tests/ui/impl-trait/different_where_bounds.rs @@ -0,0 +1,27 @@ +//! This test checks that the param env canonicalization cache +//! does not end up with inconsistent values. + +//@ check-pass + +pub fn poison1() -> impl Sized +where + (): 'static, +{ +} +pub fn poison2() -> impl Sized +where + (): 'static, +{ + define_by_query((poison2, ())); +} +pub fn poison3() -> impl Sized +where + (): 'static, +{ +} + +trait Query {} +impl<Out, F: Fn() -> Out> Query for (F, Out) {} +fn define_by_query(_: impl Query) {} + +fn main() {} diff --git a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr b/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr deleted file mode 100644 index e4c8aec3973..00000000000 --- a/tests/ui/impl-trait/equality-in-canonical-query.clone.stderr +++ /dev/null @@ -1,23 +0,0 @@ -note: no errors encountered even though delayed bugs were created - -note: those delayed bugs will now be shown as internal compiler errors - -error: internal compiler error: {OpaqueTypeKey { def_id: DefId(rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }) } }} - | - = - - -error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(foo::{opaque#0}) }))), bound_vars: [] } } } - --> $DIR/equality-in-canonical-query.rs:21:5 - | -LL | same_output(foo, rpit); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - - --> $DIR/equality-in-canonical-query.rs:21:5 - | -LL | same_output(foo, rpit); - | ^^^^^^^^^^^^^^^^^^^^^^ - -query stack during panic: -end of query stack diff --git a/tests/ui/impl-trait/equality-in-canonical-query.rs b/tests/ui/impl-trait/equality-in-canonical-query.rs index 6a32f4bec76..2b8f6ce1b07 100644 --- a/tests/ui/impl-trait/equality-in-canonical-query.rs +++ b/tests/ui/impl-trait/equality-in-canonical-query.rs @@ -1,15 +1,6 @@ // issue: #116877 //@ revisions: sized clone -//@[sized] check-pass -//@[clone] known-bug: #108498 -//@[clone] failure-status: 101 -//@[clone] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId(" -//@[clone] normalize-stderr-test: "(?m)note: we would appreciate a bug report.*\n\n" -> "" -//@[clone] normalize-stderr-test: "(?m)note: rustc.*running on.*\n\n" -> "" -//@[clone] normalize-stderr-test: "(?m)note: compiler flags.*\n\n" -> "" -//@[clone] normalize-stderr-test: "(?m)note: delayed at.*$" -> "" -//@[clone] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> "" -//@[clone] normalize-stderr-test: "(?m)^ *at .*\n" -> "" +//@ check-pass #[cfg(sized)] fn rpit() -> impl Sized {} #[cfg(clone)] fn rpit() -> impl Clone {} diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs new file mode 100644 index 00000000000..994a5073947 --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.rs @@ -0,0 +1,42 @@ +// ICE failed to resolve instance for <fn() -> impl MyFnOnce ... +// issue: rust-lang/rust#105488 +//@ build-fail +//~^^^ ERROR overflow evaluating the requirement `fn() -> impl MyFnOnce + +pub trait MyFnOnce { + type Output; + + fn call_my_fn_once(self) -> Self::Output; +} + +pub struct WrapFnOnce<F>(F); + +impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for WrapFnOnce<F> { + type Output = D::Output; + + fn call_my_fn_once(self) -> Self::Output { + D::call_my_fn_once(self.0()) + } +} + +impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for F { + type Output = D::Output; + + fn call_my_fn_once(self) -> Self::Output { + D::call_my_fn_once(self()) + } +} + +pub fn my_fn_1() -> impl MyFnOnce { + my_fn_2 +} + +pub fn my_fn_2() -> impl MyFnOnce { + WrapFnOnce(my_fn_1) +} + +fn main() { + let v = my_fn_1(); + + let _ = v.call_my_fn_once(); +} diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr new file mode 100644 index 00000000000..c2782b79d90 --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-105488.stderr @@ -0,0 +1,16 @@ +error[E0275]: overflow evaluating the requirement `fn() -> impl MyFnOnce {my_fn_2}: MyFnOnce` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`failed_to_resolve_instance_ice_105488`) +note: required for `WrapFnOnce<fn() -> impl MyFnOnce {my_fn_1}>` to implement `MyFnOnce` + --> $DIR/failed-to-resolve-instance-ice-105488.rs:14:37 + | +LL | impl<F: FnOnce() -> D, D: MyFnOnce> MyFnOnce for WrapFnOnce<F> { + | -------- ^^^^^^^^ ^^^^^^^^^^^^^ + | | + | unsatisfied trait bound introduced here + = note: 126 redundant requirements hidden + = note: required for `WrapFnOnce<fn() -> impl MyFnOnce {my_fn_1}>` to implement `MyFnOnce` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs new file mode 100644 index 00000000000..977827f3b55 --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.rs @@ -0,0 +1,20 @@ +// ICE failed to resolve instance for ... +// issue: rust-lang/rust#123145 +//@ build-fail +//~^^^ ERROR overflow evaluating the requirement `(fn() -> impl Handler + +trait Handler { + fn handle(&self) {} +} + +impl<H: Handler, F: Fn() -> H> Handler for F {} + +impl<L: Handler> Handler for (L,) {} + +fn one() -> impl Handler { + (one,) +} + +fn main() { + one.handle(); +} diff --git a/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr new file mode 100644 index 00000000000..f61e8c2f8df --- /dev/null +++ b/tests/ui/impl-trait/failed-to-resolve-instance-ice-123145.stderr @@ -0,0 +1,15 @@ +error[E0275]: overflow evaluating the requirement `(fn() -> impl Handler {one},): Handler` + | +note: required for `fn() -> impl Handler {one}` to implement `Handler` + --> $DIR/failed-to-resolve-instance-ice-123145.rs:10:32 + | +LL | impl<H: Handler, F: Fn() -> H> Handler for F {} + | ------- ^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: 2 redundant requirements hidden + = note: required for `fn() -> impl Handler {one}` to implement `Handler` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/nested-hkl-lifetime.rs b/tests/ui/impl-trait/nested-hkl-lifetime.rs new file mode 100644 index 00000000000..089ceca6777 --- /dev/null +++ b/tests/ui/impl-trait/nested-hkl-lifetime.rs @@ -0,0 +1,32 @@ +//@ check-pass + +use std::iter::FromIterator; + +struct DynamicAlt<P>(P); + +impl<P> FromIterator<P> for DynamicAlt<P> { + fn from_iter<T: IntoIterator<Item = P>>(_iter: T) -> Self { + loop {} + } +} + +fn owned_context<I, F>(_: F) -> impl FnMut(I) -> I { + |i| i +} + +trait Parser<I> {} + +impl<T, I> Parser<I> for T where T: FnMut(I) -> I {} + +fn alt<I, P: Parser<I>>(_: DynamicAlt<P>) -> impl FnMut(I) -> I { + |i| i +} + +fn rule_to_parser<'c>() -> impl Parser<&'c str> { + move |input| { + let v: Vec<()> = vec![]; + alt(v.iter().map(|()| owned_context(rule_to_parser())).collect::<DynamicAlt<_>>())(input) + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.rs b/tests/ui/impl-trait/nested-rpit-hrtb.rs index a696e1710f0..9b18aceb4a7 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.rs +++ b/tests/ui/impl-trait/nested-rpit-hrtb.rs @@ -44,7 +44,7 @@ fn one_hrtb_mention_fn_outlives<'b>() -> impl for<'a> Foo<'a, Assoc = impl Sized // This should resolve. fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} -//~^ ERROR type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>` +//~^ ERROR the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied // This should resolve. fn one_hrtb_mention_fn_outlives_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Sized + 'b> {} diff --git a/tests/ui/impl-trait/nested-rpit-hrtb.stderr b/tests/ui/impl-trait/nested-rpit-hrtb.stderr index 64f801ea685..2fa036f35fa 100644 --- a/tests/ui/impl-trait/nested-rpit-hrtb.stderr +++ b/tests/ui/impl-trait/nested-rpit-hrtb.stderr @@ -86,13 +86,12 @@ note: lifetime declared here LL | fn one_hrtb_trait_param_uses() -> impl for<'a> Bar<'a, Assoc = impl Qux<'a>> {} | ^^ -error[E0283]: type annotations needed: cannot satisfy `for<'a> &'a (): Qux<'b>` +error[E0277]: the trait bound `for<'a> &'a (): Qux<'b>` is not satisfied --> $DIR/nested-rpit-hrtb.rs:46:79 | LL | fn one_hrtb_mention_fn_trait_param_uses<'b>() -> impl for<'a> Bar<'a, Assoc = impl Qux<'b>> {} - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ the trait `for<'a> Qux<'b>` is not implemented for `&'a ()` | - = note: cannot satisfy `for<'a> &'a (): Qux<'b>` = help: the trait `Qux<'_>` is implemented for `()` = help: for that trait implementation, expected `()`, found `&'a ()` @@ -125,5 +124,5 @@ LL | fn two_htrb_outlives_uses() -> impl for<'a> Bar<'a, Assoc = impl for<'b> Si error: aborting due to 11 previous errors -Some errors have detailed explanations: E0261, E0277, E0283, E0657. +Some errors have detailed explanations: E0261, E0277, E0657. For more information about an error, try `rustc --explain E0261`. diff --git a/tests/ui/imports/unused-import-issue-87973.rs b/tests/ui/imports/unused-import-issue-87973.rs index b04bec07d18..1b016ff814c 100644 --- a/tests/ui/imports/unused-import-issue-87973.rs +++ b/tests/ui/imports/unused-import-issue-87973.rs @@ -4,7 +4,7 @@ // Check that attributes get removed too. See #87973. #[deprecated] #[allow(unsafe_code)] -#[cfg(not(foo))] +#[cfg(not(FALSE))] use std::fs; //~^ ERROR unused import diff --git a/tests/ui/inference/issue-80409.no-compat.stderr b/tests/ui/inference/issue-80409.no-compat.stderr index 523ca229b06..c772225be75 100644 --- a/tests/ui/inference/issue-80409.no-compat.stderr +++ b/tests/ui/inference/issue-80409.no-compat.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ImpliedOutlivesBounds { ty: &'?2 mut StateContext<'?3, usize> } } +error: internal compiler error: error performing operation: fully_perform --> $DIR/issue-80409.rs:49:30 | LL | builder.state().on_entry(|_| {}); diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs index 1c94169a2e5..75f406232e2 100644 --- a/tests/ui/inner-attrs-on-impl.rs +++ b/tests/ui/inner-attrs-on-impl.rs @@ -3,16 +3,16 @@ struct Foo; impl Foo { - #![cfg(cfg_that_surely_doesnt_exist)] + #![cfg(FALSE)] fn method(&self) -> bool { false } } impl Foo { - #![cfg(not(cfg_that_surely_doesnt_exist))] + #![cfg(not(FALSE))] // check that we don't eat attributes too eagerly. - #[cfg(cfg_that_surely_doesnt_exist)] + #[cfg(FALSE)] fn method(&self) -> bool { false } fn method(&self) -> bool { true } diff --git a/tests/ui/instrument-coverage/off-values.rs b/tests/ui/instrument-coverage/off-values.rs index bd13e5d7495..60222d43b23 100644 --- a/tests/ui/instrument-coverage/off-values.rs +++ b/tests/ui/instrument-coverage/off-values.rs @@ -1,9 +1,9 @@ //@ check-pass -//@ revisions: n no off false zero +//@ revisions: n no off _false zero //@ [n] compile-flags: -Cinstrument-coverage=n //@ [no] compile-flags: -Cinstrument-coverage=no //@ [off] compile-flags: -Cinstrument-coverage=off -//@ [false] compile-flags: -Cinstrument-coverage=false +//@ [_false] compile-flags: -Cinstrument-coverage=false //@ [zero] compile-flags: -Cinstrument-coverage=0 fn main() {} diff --git a/tests/ui/intrinsics/incorrect-transmute.rs b/tests/ui/intrinsics/incorrect-transmute.rs new file mode 100644 index 00000000000..4f1d1491ec9 --- /dev/null +++ b/tests/ui/intrinsics/incorrect-transmute.rs @@ -0,0 +1,8 @@ +fn main() { + transmute(); // does not ICE +} + +extern "rust-intrinsic" fn transmute() {} +//~^ ERROR intrinsic has wrong number of type parameters: found 0, expected 2 +//~| ERROR intrinsics are subject to change +//~| ERROR intrinsic must be in `extern "rust-intrinsic" { ... }` block diff --git a/tests/ui/intrinsics/incorrect-transmute.stderr b/tests/ui/intrinsics/incorrect-transmute.stderr new file mode 100644 index 00000000000..20b95925b76 --- /dev/null +++ b/tests/ui/intrinsics/incorrect-transmute.stderr @@ -0,0 +1,25 @@ +error[E0658]: intrinsics are subject to change + --> $DIR/incorrect-transmute.rs:5:8 + | +LL | extern "rust-intrinsic" fn transmute() {} + | ^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(intrinsics)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0094]: intrinsic has wrong number of type parameters: found 0, expected 2 + --> $DIR/incorrect-transmute.rs:5:37 + | +LL | extern "rust-intrinsic" fn transmute() {} + | ^ expected 2 type parameters + +error: intrinsic must be in `extern "rust-intrinsic" { ... }` block + --> $DIR/incorrect-transmute.rs:5:40 + | +LL | extern "rust-intrinsic" fn transmute() {} + | ^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0094, E0658. +For more information about an error, try `rustc --explain E0094`. diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/issues/issue-11004.rs index 10ef1f5e3b5..09d5476dbe6 100644 --- a/tests/ui/issues/issue-11004.rs +++ b/tests/ui/issues/issue-11004.rs @@ -2,14 +2,14 @@ use std::mem; struct A { x: i32, y: f64 } -#[cfg(not(works))] +#[cfg(not(FALSE))] unsafe fn access(n:*mut A) -> (i32, f64) { let x : i32 = n.x; //~ no field `x` on type `*mut A` let y : f64 = n.y; //~ no field `y` on type `*mut A` (x, y) } -#[cfg(works)] +#[cfg(FALSE)] unsafe fn access(n:*mut A) -> (i32, f64) { let x : i32 = (*n).x; let y : f64 = (*n).y; diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/issues/issue-11085.rs index c4a9f5f69bd..300be10226c 100644 --- a/tests/ui/issues/issue-11085.rs +++ b/tests/ui/issues/issue-11085.rs @@ -5,7 +5,7 @@ //@ pretty-expanded FIXME #23616 struct Foo { - #[cfg(fail)] + #[cfg(FALSE)] bar: baz, foo: isize, } @@ -17,18 +17,18 @@ struct Foo2 { enum Bar1 { Bar1_1, - #[cfg(fail)] + #[cfg(FALSE)] Bar1_2(NotAType), } enum Bar2 { - #[cfg(fail)] + #[cfg(FALSE)] Bar2_1(NotAType), } enum Bar3 { Bar3_1 { - #[cfg(fail)] + #[cfg(FALSE)] foo: isize, bar: isize, } diff --git a/tests/ui/issues/issue-16819.rs b/tests/ui/issues/issue-16819.rs index 320695118d5..e2b10909177 100644 --- a/tests/ui/issues/issue-16819.rs +++ b/tests/ui/issues/issue-16819.rs @@ -3,7 +3,7 @@ // `#[cfg]` on struct field permits empty unusable struct struct S { - #[cfg(untrue)] + #[cfg(FALSE)] a: int, } diff --git a/tests/ui/issues/issue-21763.rs b/tests/ui/issues/issue-21763.rs index a349253063c..1d0a0705cbb 100644 --- a/tests/ui/issues/issue-21763.rs +++ b/tests/ui/issues/issue-21763.rs @@ -1,6 +1,6 @@ // Regression test for HashMap only impl'ing Send/Sync if its contents do -//@ normalize-stderr-test: "\S+hashbrown-\S+" -> "$$HASHBROWN_SRC_LOCATION" +//@ normalize-stderr-test: "\S+[\\/]hashbrown\S+" -> "$$HASHBROWN_SRC_LOCATION" use std::collections::HashMap; use std::rc::Rc; diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.rs b/tests/ui/layout/base-layout-is-sized-ice-123078.rs new file mode 100644 index 00000000000..b1c33e15075 --- /dev/null +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.rs @@ -0,0 +1,17 @@ +// ICE !base.layout().is_sized() +// issue: rust-lang/rust#123078 + +struct S { + a: [u8], + //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time + b: (), +} + +const C: S = unsafe { std::mem::transmute(()) }; +//~^ ERROR cannot transmute between types of different sizes, or dependently-sized types +const _: [(); { + C; + 0 +}] = []; + +pub fn main() {} diff --git a/tests/ui/layout/base-layout-is-sized-ice-123078.stderr b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr new file mode 100644 index 00000000000..7e0a41a4367 --- /dev/null +++ b/tests/ui/layout/base-layout-is-sized-ice-123078.stderr @@ -0,0 +1,31 @@ +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/base-layout-is-sized-ice-123078.rs:5:8 + | +LL | a: [u8], + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` + = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | a: &[u8], + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | a: Box<[u8]>, + | ++++ + + +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/base-layout-is-sized-ice-123078.rs:10:23 + | +LL | const C: S = unsafe { std::mem::transmute(()) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `()` (0 bits) + = note: target type: `S` (this type does not have a fixed size) + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0512. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs new file mode 100644 index 00000000000..96c993035ef --- /dev/null +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.rs @@ -0,0 +1,10 @@ +// ICE Unexpected unsized type tail: &ReStatic [u8] +// issue: rust-lang/rust#122488 +use std::ops::Deref; + +struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U); +//~^ ERROR the size for values of type `V` cannot be known at compilation time + +const DATA: *const ArenaSet<Vec<u8>> = std::ptr::null_mut(); + +pub fn main() {} diff --git a/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr new file mode 100644 index 00000000000..f39cb29868a --- /dev/null +++ b/tests/ui/layout/issue-unsized-tail-restatic-ice-122488.stderr @@ -0,0 +1,27 @@ +error[E0277]: the size for values of type `V` cannot be known at compilation time + --> $DIR/issue-unsized-tail-restatic-ice-122488.rs:5:61 + | +LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U); + | -------------------------------- ^ doesn't have a size known at compile-time + | | + | this type parameter needs to be `Sized` + | + = note: only the last field of a struct may have a dynamically sized type + = help: change the field's type to have a statically known size +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(V, U); +LL + struct ArenaSet<U: Deref, V = <U as Deref>::Target>(V, U); + | +help: borrowed types always have a statically known size + | +LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(&V, U); + | + +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | struct ArenaSet<U: Deref, V: ?Sized = <U as Deref>::Target>(Box<V>, U); + | ++++ + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/issues/auxiliary/issue-12133-dylib.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib.rs index 8bd2b3353b8..8bd2b3353b8 100644 --- a/tests/ui/issues/auxiliary/issue-12133-dylib.rs +++ b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib.rs diff --git a/tests/ui/issues/auxiliary/issue-12133-dylib2.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib2.rs index 42e13ad6908..42e13ad6908 100644 --- a/tests/ui/issues/auxiliary/issue-12133-dylib2.rs +++ b/tests/ui/linkage-attr/auxiliary/issue-12133-dylib2.rs diff --git a/tests/ui/issues/auxiliary/issue-12133-rlib.rs b/tests/ui/linkage-attr/auxiliary/issue-12133-rlib.rs index 1adaf2b0379..1adaf2b0379 100644 --- a/tests/ui/issues/auxiliary/issue-12133-rlib.rs +++ b/tests/ui/linkage-attr/auxiliary/issue-12133-rlib.rs diff --git a/tests/ui/linkage-attr/framework.omit.stderr b/tests/ui/linkage-attr/framework.omit.stderr index 5cb4d391437..23e017cb012 100644 --- a/tests/ui/linkage-attr/framework.omit.stderr +++ b/tests/ui/linkage-attr/framework.omit.stderr @@ -1,4 +1,4 @@ -error: linking with `cc` failed: exit status: 1 +error: linking with `LINKER` failed: exit status: 1 | ld: Undefined symbols: _CFRunLoopGetTypeID, referenced from: diff --git a/tests/ui/linkage-attr/framework.rs b/tests/ui/linkage-attr/framework.rs index 662ef4c429d..824adf62206 100644 --- a/tests/ui/linkage-attr/framework.rs +++ b/tests/ui/linkage-attr/framework.rs @@ -6,8 +6,10 @@ //@ [weak]run-pass //@ [both]run-pass -// The linker's exact error output changes between Xcode versions. +// The linker's exact error output changes between Xcode versions, depends on +// linker invocation details, and the linker sometimes outputs more warnings. //@ compare-output-lines-by-subset +//@ normalize-stderr-test: "linking with `.*` failed" -> "linking with `LINKER` failed" //@ normalize-stderr-test: "Undefined symbols for architecture .*" -> "ld: Undefined symbols:" //@ normalize-stderr-test: "._CFRunLoopGetTypeID.," -> "_CFRunLoopGetTypeID," diff --git a/tests/ui/issues/issue-12133-1.rs b/tests/ui/linkage-attr/issue-12133-1.rs index dc3f7f33da1..dc3f7f33da1 100644 --- a/tests/ui/issues/issue-12133-1.rs +++ b/tests/ui/linkage-attr/issue-12133-1.rs diff --git a/tests/ui/issues/issue-12133-2.rs b/tests/ui/linkage-attr/issue-12133-2.rs index 55742a1b383..55742a1b383 100644 --- a/tests/ui/issues/issue-12133-2.rs +++ b/tests/ui/linkage-attr/issue-12133-2.rs diff --git a/tests/ui/issues/issue-12133-3.rs b/tests/ui/linkage-attr/issue-12133-3.rs index a34c075d64d..a34c075d64d 100644 --- a/tests/ui/issues/issue-12133-3.rs +++ b/tests/ui/linkage-attr/issue-12133-3.rs diff --git a/tests/ui/lint/auxiliary/non_local_macro.rs b/tests/ui/lint/non-local-defs/auxiliary/non_local_macro.rs index 8c0ff8adda1..8c0ff8adda1 100644 --- a/tests/ui/lint/auxiliary/non_local_macro.rs +++ b/tests/ui/lint/non-local-defs/auxiliary/non_local_macro.rs diff --git a/tests/ui/lint/non-local-defs/cargo-update.rs b/tests/ui/lint/non-local-defs/cargo-update.rs new file mode 100644 index 00000000000..8b8c15795d3 --- /dev/null +++ b/tests/ui/lint/non-local-defs/cargo-update.rs @@ -0,0 +1,20 @@ +//@ check-pass +//@ edition:2021 +//@ aux-build:non_local_macro.rs +// +// To suggest any Cargo specific help/note rustc wants +// the `CARGO_CRATE_NAME` env to be set, so we set it +//@ rustc-env:CARGO_CRATE_NAME=non_local_def +// +// and since we specifically want to check the presence +// of the `cargo update` suggestion we assert it here. +//@ error-pattern: `cargo update -p non_local_macro` + +extern crate non_local_macro; + +struct LocalStruct; + +non_local_macro::non_local_impl!(LocalStruct); +//~^ WARN non-local `impl` definition + +fn main() {} diff --git a/tests/ui/lint/non-local-defs/cargo-update.stderr b/tests/ui/lint/non-local-defs/cargo-update.stderr new file mode 100644 index 00000000000..e9e33b9aa17 --- /dev/null +++ b/tests/ui/lint/non-local-defs/cargo-update.stderr @@ -0,0 +1,16 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/cargo-update.rs:17:1 + | +LL | non_local_macro::non_local_impl!(LocalStruct); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `_IMPL_DEBUG` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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 macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` + = note: `#[warn(non_local_definitions)]` on by default + = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/lint/non-local-defs/consts.rs b/tests/ui/lint/non-local-defs/consts.rs new file mode 100644 index 00000000000..2652447dcf5 --- /dev/null +++ b/tests/ui/lint/non-local-defs/consts.rs @@ -0,0 +1,88 @@ +//@ check-pass +//@ edition:2021 +//@ rustc-env:CARGO_CRATE_NAME=non_local_def + +#![feature(inline_const)] + +struct Test; + +trait Uto {} +const Z: () = { + trait Uto1 {} + + impl Uto1 for Test {} // the trait is local, don't lint + + impl Uto for &Test {} + //~^ WARN non-local `impl` definition +}; + +trait Ano {} +const _: () = { + impl Ano for &Test {} // ignored since the parent is an anon-const +}; + +trait Uto2 {} +static A: u32 = { + impl Uto2 for Test {} + //~^ WARN non-local `impl` definition + + 1 +}; + +trait Uto3 {} +const B: u32 = { + impl Uto3 for Test {} + //~^ WARN non-local `impl` definition + + trait Uto4 {} + impl Uto4 for Test {} + + 1 +}; + +trait Uto5 {} +fn main() { + impl Test { + //~^ WARN non-local `impl` definition + fn foo() {} + } + + + const { + impl Test { + //~^ WARN non-local `impl` definition + fn hoo() {} + } + + 1 + }; + + const _: u32 = { + impl Test { + //~^ WARN non-local `impl` definition + fn foo2() {} + } + + 1 + }; +} + +trait Uto9 {} +trait Uto10 {} +const _: u32 = { + let _a = || { + impl Uto9 for Test {} + //~^ WARN non-local `impl` definition + + 1 + }; + + type A = [u32; { + impl Uto10 for Test {} + //~^ WARN non-local `impl` definition + + 1 + }]; + + 1 +}; diff --git a/tests/ui/lint/non-local-defs/consts.stderr b/tests/ui/lint/non-local-defs/consts.stderr new file mode 100644 index 00000000000..5563ea9d93f --- /dev/null +++ b/tests/ui/lint/non-local-defs/consts.stderr @@ -0,0 +1,103 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:15:5 + | +LL | const Z: () = { + | - help: use a const-anon item to suppress this lint: `_` +... +LL | impl Uto for &Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `Z` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:26:5 + | +LL | impl Uto2 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current static `A` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:34:5 + | +LL | impl Uto3 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant `B` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:45:5 + | +LL | / impl Test { +LL | | +LL | | fn foo() {} +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:52:9 + | +LL | / impl Test { +LL | | +LL | | fn hoo() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current inline constant `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:61:9 + | +LL | / impl Test { +LL | | +LL | | fn foo2() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current constant `_` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:74:9 + | +LL | impl Uto9 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/consts.rs:81:9 + | +LL | impl Uto10 for Test {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: 8 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.rs b/tests/ui/lint/non-local-defs/exhaustive-trait.rs new file mode 100644 index 00000000000..40d2314460f --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.rs @@ -0,0 +1,48 @@ +//@ check-pass +//@ edition:2021 + +struct Dog; + +fn main() { + impl PartialEq<()> for Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &()) -> bool { + todo!() + } + } + + impl PartialEq<()> for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &()) -> bool { + todo!() + } + } + + impl PartialEq<Dog> for () { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &Dog) -> bool { + todo!() + } + } + + impl PartialEq<&Dog> for () { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &&Dog) -> bool { + todo!() + } + } + + impl PartialEq<Dog> for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &Dog) -> bool { + todo!() + } + } + + impl PartialEq<&Dog> for &Dog { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &&Dog) -> bool { + todo!() + } + } +} diff --git a/tests/ui/lint/non-local-defs/exhaustive-trait.stderr b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr new file mode 100644 index 00000000000..8d58d4dd27c --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive-trait.stderr @@ -0,0 +1,99 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:7:5 + | +LL | / impl PartialEq<()> for Dog { +LL | | +LL | | fn eq(&self, _: &()) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:14:5 + | +LL | / impl PartialEq<()> for &Dog { +LL | | +LL | | fn eq(&self, _: &()) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:21:5 + | +LL | / impl PartialEq<Dog> for () { +LL | | +LL | | fn eq(&self, _: &Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:28:5 + | +LL | / impl PartialEq<&Dog> for () { +LL | | +LL | | fn eq(&self, _: &&Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:35:5 + | +LL | / impl PartialEq<Dog> for &Dog { +LL | | +LL | | fn eq(&self, _: &Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive-trait.rs:42:5 + | +LL | / impl PartialEq<&Dog> for &Dog { +LL | | +LL | | fn eq(&self, _: &&Dog) -> bool { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: 6 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/exhaustive.rs b/tests/ui/lint/non-local-defs/exhaustive.rs new file mode 100644 index 00000000000..2fb30f4344a --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive.rs @@ -0,0 +1,84 @@ +//@ check-pass +//@ edition:2021 + +use std::fmt::Display; + +trait Trait {} +struct Test; + +fn main() { + impl Test { + //~^ WARN non-local `impl` definition + fn foo() {} + } + + impl Display for Test { + //~^ WARN non-local `impl` definition + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl dyn Trait {} + //~^ WARN non-local `impl` definition + + impl<T: Trait> Trait for Vec<T> { } + //~^ WARN non-local `impl` definition + + impl Trait for &dyn Trait {} + //~^ WARN non-local `impl` definition + + impl Trait for *mut Test {} + //~^ WARN non-local `impl` definition + + impl Trait for *mut [Test] {} + //~^ WARN non-local `impl` definition + + impl Trait for [Test; 8] {} + //~^ WARN non-local `impl` definition + + impl Trait for (Test,) {} + //~^ WARN non-local `impl` definition + + impl Trait for fn(Test) -> () {} + //~^ WARN non-local `impl` definition + + impl Trait for fn() -> Test {} + //~^ WARN non-local `impl` definition + + let _a = || { + impl Trait for Test {} + //~^ WARN non-local `impl` definition + + 1 + }; + + struct InsideMain; + + impl Trait for *mut InsideMain {} + //~^ WARN non-local `impl` definition + impl Trait for *mut [InsideMain] {} + //~^ WARN non-local `impl` definition + impl Trait for [InsideMain; 8] {} + //~^ WARN non-local `impl` definition + impl Trait for (InsideMain,) {} + //~^ WARN non-local `impl` definition + impl Trait for fn(InsideMain) -> () {} + //~^ WARN non-local `impl` definition + impl Trait for fn() -> InsideMain {} + //~^ WARN non-local `impl` definition + + fn inside_inside() { + impl Display for InsideMain { + //~^ WARN non-local `impl` definition + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl InsideMain { + //~^ WARN non-local `impl` definition + fn bar() {} + } + } +} diff --git a/tests/ui/lint/non-local-defs/exhaustive.stderr b/tests/ui/lint/non-local-defs/exhaustive.stderr new file mode 100644 index 00000000000..b3697969c4f --- /dev/null +++ b/tests/ui/lint/non-local-defs/exhaustive.stderr @@ -0,0 +1,239 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:10:5 + | +LL | / impl Test { +LL | | +LL | | fn foo() {} +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:15:5 + | +LL | / impl Display for Test { +LL | | +LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:22:5 + | +LL | impl dyn Trait {} + | ^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:25:5 + | +LL | impl<T: Trait> Trait for Vec<T> { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:28:5 + | +LL | impl Trait for &dyn Trait {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:31:5 + | +LL | impl Trait for *mut Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:34:5 + | +LL | impl Trait for *mut [Test] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:37:5 + | +LL | impl Trait for [Test; 8] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:40:5 + | +LL | impl Trait for (Test,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:43:5 + | +LL | impl Trait for fn(Test) -> () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:46:5 + | +LL | impl Trait for fn() -> Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:50:9 + | +LL | impl Trait for Test {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:58:5 + | +LL | impl Trait for *mut InsideMain {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:60:5 + | +LL | impl Trait for *mut [InsideMain] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:62:5 + | +LL | impl Trait for [InsideMain; 8] {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:64:5 + | +LL | impl Trait for (InsideMain,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:66:5 + | +LL | impl Trait for fn(InsideMain) -> () {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:68:5 + | +LL | impl Trait for fn() -> InsideMain {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:72:9 + | +LL | / impl Display for InsideMain { +LL | | +LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +LL | | todo!() +LL | | } +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/exhaustive.rs:79:9 + | +LL | / impl InsideMain { +LL | | +LL | | fn bar() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: 20 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.rs b/tests/ui/lint/non-local-defs/from-local-for-global.rs new file mode 100644 index 00000000000..0ab3a6b1988 --- /dev/null +++ b/tests/ui/lint/non-local-defs/from-local-for-global.rs @@ -0,0 +1,103 @@ +//@ check-pass +//@ edition:2021 + +#![feature(inline_const)] + +struct Cat; +struct Wrap<T>(T); + +fn main() { + impl From<Cat> for () { + //~^ WARN non-local `impl` definition + fn from(_: Cat) -> () { + todo!() + } + } + + #[derive(Debug)] + struct Elephant; + + impl From<Wrap<Wrap<Elephant>>> for () { + //~^ WARN non-local `impl` definition + fn from(_: Wrap<Wrap<Elephant>>) -> Self { + todo!() + } + } +} + +pub trait StillNonLocal {} + +impl StillNonLocal for &str {} + +fn only_global() { + struct Foo; + impl StillNonLocal for &Foo {} + //~^ WARN non-local `impl` definition +} + +struct GlobalSameFunction; + +fn same_function() { + struct Local1(GlobalSameFunction); + impl From<Local1> for GlobalSameFunction { + //~^ WARN non-local `impl` definition + fn from(x: Local1) -> GlobalSameFunction { + x.0 + } + } + + struct Local2(GlobalSameFunction); + impl From<Local2> for GlobalSameFunction { + //~^ WARN non-local `impl` definition + fn from(x: Local2) -> GlobalSameFunction { + x.0 + } + } +} + +struct GlobalDifferentFunction; + +fn diff_function_1() { + struct Local(GlobalDifferentFunction); + + impl From<Local> for GlobalDifferentFunction { + // FIXME(Urgau): Should warn but doesn't since we currently consider + // the other impl to be "global", but that's not the case for the type-system + fn from(x: Local) -> GlobalDifferentFunction { + x.0 + } + } +} + +fn diff_function_2() { + struct Local(GlobalDifferentFunction); + + impl From<Local> for GlobalDifferentFunction { + // FIXME(Urgau): Should warn but doesn't since we currently consider + // the other impl to be "global", but that's not the case for the type-system + fn from(x: Local) -> GlobalDifferentFunction { + x.0 + } + } +} + +// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895 +fn commonly_reported() { + struct Local(u8); + impl From<Local> for u8 { + fn from(x: Local) -> u8 { + x.0 + } + } +} + +// https://github.com/rust-lang/rust/issues/121621#issue-2153187542 +pub trait Serde {} + +impl Serde for &[u8] {} +impl Serde for &str {} + +fn serde() { + struct Thing; + impl Serde for &Thing {} +} diff --git a/tests/ui/lint/non-local-defs/from-local-for-global.stderr b/tests/ui/lint/non-local-defs/from-local-for-global.stderr new file mode 100644 index 00000000000..bd592a72157 --- /dev/null +++ b/tests/ui/lint/non-local-defs/from-local-for-global.stderr @@ -0,0 +1,78 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:10:5 + | +LL | / impl From<Cat> for () { +LL | | +LL | | fn from(_: Cat) -> () { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:20:5 + | +LL | / impl From<Wrap<Wrap<Elephant>>> for () { +LL | | +LL | | fn from(_: Wrap<Wrap<Elephant>>) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:34:5 + | +LL | impl StillNonLocal for &Foo {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `only_global` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:42:5 + | +LL | / impl From<Local1> for GlobalSameFunction { +LL | | +LL | | fn from(x: Local1) -> GlobalSameFunction { +LL | | x.0 +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `same_function` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/from-local-for-global.rs:50:5 + | +LL | / impl From<Local2> for GlobalSameFunction { +LL | | +LL | | fn from(x: Local2) -> GlobalSameFunction { +LL | | x.0 +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `same_function` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: 5 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/generics.rs b/tests/ui/lint/non-local-defs/generics.rs new file mode 100644 index 00000000000..0f526526dba --- /dev/null +++ b/tests/ui/lint/non-local-defs/generics.rs @@ -0,0 +1,88 @@ +//@ check-pass +//@ edition:2021 + +trait Global {} + +fn main() { + trait Local {}; + + impl<T: Local> Global for Vec<T> { } + //~^ WARN non-local `impl` definition +} + +trait Uto7 {} +trait Uto8 {} + +struct Test; + +fn bad() { + struct Local; + impl Uto7 for Test where Local: std::any::Any {} + //~^ WARN non-local `impl` definition + + impl<T> Uto8 for T {} + //~^ WARN non-local `impl` definition +} + +struct UwU<T>(T); + +fn fun() { + #[derive(Debug)] + struct OwO; + impl Default for UwU<OwO> { + //~^ WARN non-local `impl` definition + fn default() -> Self { + UwU(OwO) + } + } +} + +fn meow() { + #[derive(Debug)] + struct Cat; + impl AsRef<Cat> for () { + //~^ WARN non-local `impl` definition + fn as_ref(&self) -> &Cat { &Cat } + } +} + +struct G; + +fn fun2() { + #[derive(Debug, Default)] + struct B; + impl PartialEq<B> for G { + //~^ WARN non-local `impl` definition + fn eq(&self, _: &B) -> bool { + true + } + } +} + +struct Wrap<T>(T); + +impl Wrap<Wrap<Wrap<()>>> {} + +fn rawr() { + struct Lion; + + impl From<Wrap<Wrap<Lion>>> for () { + //~^ WARN non-local `impl` definition + fn from(_: Wrap<Wrap<Lion>>) -> Self { + todo!() + } + } + + impl From<()> for Wrap<Lion> { + //~^ WARN non-local `impl` definition + fn from(_: ()) -> Self { + todo!() + } + } +} + +fn side_effects() { + dbg!(().as_ref()); // prints `Cat` + dbg!(UwU::default().0); + let _ = G::eq(&G, dbg!(&<_>::default())); +} diff --git a/tests/ui/lint/non-local-defs/generics.stderr b/tests/ui/lint/non-local-defs/generics.stderr new file mode 100644 index 00000000000..681d9e45e7a --- /dev/null +++ b/tests/ui/lint/non-local-defs/generics.stderr @@ -0,0 +1,114 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:9:5 + | +LL | impl<T: Local> Global for Vec<T> { } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `main` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:20:5 + | +LL | impl Uto7 for Test where Local: std::any::Any {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `bad` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:23:5 + | +LL | impl<T> Uto8 for T {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current function `bad` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:32:5 + | +LL | / impl Default for UwU<OwO> { +LL | | +LL | | fn default() -> Self { +LL | | UwU(OwO) +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `fun` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:43:5 + | +LL | / impl AsRef<Cat> for () { +LL | | +LL | | fn as_ref(&self) -> &Cat { &Cat } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `meow` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:54:5 + | +LL | / impl PartialEq<B> for G { +LL | | +LL | | fn eq(&self, _: &B) -> bool { +LL | | true +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `fun2` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:69:5 + | +LL | / impl From<Wrap<Wrap<Lion>>> for () { +LL | | +LL | | fn from(_: Wrap<Wrap<Lion>>) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `rawr` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/generics.rs:76:5 + | +LL | / impl From<()> for Wrap<Lion> { +LL | | +LL | | fn from(_: ()) -> Self { +LL | | todo!() +LL | | } +LL | | } + | |_____^ + | + = help: move this `impl` block outside the of the current function `rawr` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: 8 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.rs b/tests/ui/lint/non-local-defs/inside-macro_rules.rs new file mode 100644 index 00000000000..9f21cc89852 --- /dev/null +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.rs @@ -0,0 +1,17 @@ +//@ check-pass +//@ edition:2021 + +macro_rules! m { + () => { + trait MacroTrait {} + struct OutsideStruct; + fn my_func() { + impl MacroTrait for OutsideStruct {} + //~^ WARN non-local `impl` definition + } + } +} + +m!(); + +fn main() {} diff --git a/tests/ui/lint/non-local-defs/inside-macro_rules.stderr b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr new file mode 100644 index 00000000000..319682b973d --- /dev/null +++ b/tests/ui/lint/non-local-defs/inside-macro_rules.stderr @@ -0,0 +1,18 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/inside-macro_rules.rs:9:13 + | +LL | impl MacroTrait for OutsideStruct {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | m!(); + | ---- in this macro invocation + | + = help: move this `impl` block outside the of the current function `my_func` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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: `#[warn(non_local_definitions)]` on by default + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/tests/ui/lint/non-local-defs/local.rs b/tests/ui/lint/non-local-defs/local.rs new file mode 100644 index 00000000000..166ee88c021 --- /dev/null +++ b/tests/ui/lint/non-local-defs/local.rs @@ -0,0 +1,53 @@ +//@ check-pass +//@ edition:2021 + +use std::fmt::Debug; + +trait GlobalTrait {} + +fn main() { + struct InsideMain; + + impl InsideMain { + fn foo() {} + } + + impl GlobalTrait for InsideMain {} + + impl Debug for InsideMain { + fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + todo!() + } + } + + impl PartialEq<()> for InsideMain { + fn eq(&self, _: &()) -> bool { + todo!() + } + } +} + +fn dyn_weirdness() { + trait LocalTrait {} + impl dyn LocalTrait {} + impl GlobalTrait for dyn LocalTrait {} +} + +struct Test; +mod do_not_lint_mod { + pub trait Tait {} + + impl super::Test { + fn hugo() {} + } + + impl Tait for super::Test {} +} + +fn bitflags() { + struct Flags; + + const _: () = { + impl Flags {} + }; +} diff --git a/tests/ui/lint/non-local-defs/macro_rules.rs b/tests/ui/lint/non-local-defs/macro_rules.rs new file mode 100644 index 00000000000..ed30a24903d --- /dev/null +++ b/tests/ui/lint/non-local-defs/macro_rules.rs @@ -0,0 +1,33 @@ +//@ check-pass +//@ edition:2021 +//@ aux-build:non_local_macro.rs +//@ rustc-env:CARGO_CRATE_NAME=non_local_def + +extern crate non_local_macro; + +const B: u32 = { + #[macro_export] + macro_rules! m0 { () => { } }; + //~^ WARN non-local `macro_rules!` definition + + 1 +}; + +non_local_macro::non_local_macro_rules!(my_macro); +//~^ WARN non-local `macro_rules!` definition + +fn main() { + #[macro_export] + macro_rules! m { () => { } }; + //~^ WARN non-local `macro_rules!` definition + + struct InsideMain; + + impl InsideMain { + fn bar() { + #[macro_export] + macro_rules! m2 { () => { } }; + //~^ WARN non-local `macro_rules!` definition + } + } +} diff --git a/tests/ui/lint/non-local-defs/macro_rules.stderr b/tests/ui/lint/non-local-defs/macro_rules.stderr new file mode 100644 index 00000000000..125d8e97d87 --- /dev/null +++ b/tests/ui/lint/non-local-defs/macro_rules.stderr @@ -0,0 +1,49 @@ +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:10:5 + | +LL | macro_rules! m0 { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = 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: `#[warn(non_local_definitions)]` on by default + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:16:1 + | +LL | non_local_macro::non_local_macro_rules!(my_macro); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `_MACRO_EXPORT` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = 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 macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` + = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:21:5 + | +LL | macro_rules! m { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = 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> + +warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation + --> $DIR/macro_rules.rs:29:13 + | +LL | macro_rules! m2 { () => { } }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current associated function `bar` and up 2 bodies + = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module + = 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> + +warning: 4 warnings emitted + diff --git a/tests/ui/lint/non-local-defs/weird-exprs.rs b/tests/ui/lint/non-local-defs/weird-exprs.rs new file mode 100644 index 00000000000..1d9cecea0c9 --- /dev/null +++ b/tests/ui/lint/non-local-defs/weird-exprs.rs @@ -0,0 +1,53 @@ +//@ check-pass +//@ edition:2021 + +trait Uto {} +struct Test; + +type A = [u32; { + impl Uto for *mut Test {} + //~^ WARN non-local `impl` definition + + 1 +}]; + +enum Enum { + Discr = { + impl Uto for Test {} + //~^ WARN non-local `impl` definition + + 1 + } +} + +fn main() { + let _array = [0i32; { + impl Test { + //~^ WARN non-local `impl` definition + fn bar() {} + } + + 1 + }]; + + type A = [u32; { + impl Uto for &Test {} + //~^ WARN non-local `impl` definition + + 1 + }]; + + fn a(_: [u32; { + impl Uto for &(Test,) {} + //~^ WARN non-local `impl` definition + + 1 + }]) {} + + fn b() -> [u32; { + impl Uto for &(Test,Test) {} + //~^ WARN non-local `impl` definition + + 1 + }] { todo!() } +} diff --git a/tests/ui/lint/non-local-defs/weird-exprs.stderr b/tests/ui/lint/non-local-defs/weird-exprs.stderr new file mode 100644 index 00000000000..015a0cce43b --- /dev/null +++ b/tests/ui/lint/non-local-defs/weird-exprs.stderr @@ -0,0 +1,72 @@ +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:8:5 + | +LL | impl Uto for *mut Test {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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: `#[warn(non_local_definitions)]` on by default + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:16:9 + | +LL | impl Uto for Test {} + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:25:9 + | +LL | / impl Test { +LL | | +LL | | fn bar() {} +LL | | } + | |_________^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:34:9 + | +LL | impl Uto for &Test {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:41:9 + | +LL | impl Uto for &(Test,) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: non-local `impl` definition, they should be avoided as they go against expectation + --> $DIR/weird-exprs.rs:48:9 + | +LL | impl Uto for &(Test,Test) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies + = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` + = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type + = 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> + +warning: 6 warnings emitted + diff --git a/tests/ui/lint/non_local_definitions.rs b/tests/ui/lint/non_local_definitions.rs deleted file mode 100644 index 0b43e19d1e9..00000000000 --- a/tests/ui/lint/non_local_definitions.rs +++ /dev/null @@ -1,491 +0,0 @@ -//@ check-pass -//@ edition:2021 -//@ aux-build:non_local_macro.rs -//@ rustc-env:CARGO_CRATE_NAME=non_local_def - -#![feature(inline_const)] - -extern crate non_local_macro; - -use std::fmt::{Debug, Display}; - -struct Test; - -impl Debug for Test { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } -} - -mod do_not_lint_mod { - pub trait Tait {} - - impl super::Test { - fn hugo() {} - } - - impl Tait for super::Test {} -} - -trait Uto {} -const Z: () = { - trait Uto1 {} - - impl Uto1 for Test {} // the trait is local, don't lint - - impl Uto for &Test {} - //~^ WARN non-local `impl` definition -}; - -trait Ano {} -const _: () = { - impl Ano for &Test {} // ignored since the parent is an anon-const -}; - -type A = [u32; { - impl Uto for *mut Test {} - //~^ WARN non-local `impl` definition - - 1 -}]; - -enum Enum { - Discr = { - impl Uto for Test {} - //~^ WARN non-local `impl` definition - - 1 - } -} - -trait Uto2 {} -static A: u32 = { - impl Uto2 for Test {} - //~^ WARN non-local `impl` definition - - 1 -}; - -trait Uto3 {} -const B: u32 = { - impl Uto3 for Test {} - //~^ WARN non-local `impl` definition - - #[macro_export] - macro_rules! m0 { () => { } }; - //~^ WARN non-local `macro_rules!` definition - - trait Uto4 {} - impl Uto4 for Test {} - - 1 -}; - -trait Uto5 {} -fn main() { - #[macro_export] - macro_rules! m { () => { } }; - //~^ WARN non-local `macro_rules!` definition - - impl Test { - //~^ WARN non-local `impl` definition - fn foo() {} - } - - let _array = [0i32; { - impl Test { - //~^ WARN non-local `impl` definition - fn bar() {} - } - - 1 - }]; - - const { - impl Test { - //~^ WARN non-local `impl` definition - fn hoo() {} - } - - 1 - }; - - const _: u32 = { - impl Test { - //~^ WARN non-local `impl` definition - fn foo2() {} - } - - 1 - }; - - impl Display for Test { - //~^ WARN non-local `impl` definition - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } - } - - impl dyn Uto5 {} - //~^ WARN non-local `impl` definition - - impl<T: Uto5> Uto5 for Vec<T> { } - //~^ WARN non-local `impl` definition - - impl Uto5 for &dyn Uto5 {} - //~^ WARN non-local `impl` definition - - impl Uto5 for *mut Test {} - //~^ WARN non-local `impl` definition - - impl Uto5 for *mut [Test] {} - //~^ WARN non-local `impl` definition - - impl Uto5 for [Test; 8] {} - //~^ WARN non-local `impl` definition - - impl Uto5 for (Test,) {} - //~^ WARN non-local `impl` definition - - impl Uto5 for fn(Test) -> () {} - //~^ WARN non-local `impl` definition - - impl Uto5 for fn() -> Test {} - //~^ WARN non-local `impl` definition - - let _a = || { - impl Uto5 for Test {} - //~^ WARN non-local `impl` definition - - 1 - }; - - type A = [u32; { - impl Uto5 for &Test {} - //~^ WARN non-local `impl` definition - - 1 - }]; - - fn a(_: [u32; { - impl Uto5 for &(Test,) {} - //~^ WARN non-local `impl` definition - - 1 - }]) {} - - fn b() -> [u32; { - impl Uto5 for &(Test,Test) {} - //~^ WARN non-local `impl` definition - - 1 - }] { todo!() } - - struct InsideMain; - - impl Uto5 for *mut InsideMain {} - //~^ WARN non-local `impl` definition - impl Uto5 for *mut [InsideMain] {} - //~^ WARN non-local `impl` definition - impl Uto5 for [InsideMain; 8] {} - //~^ WARN non-local `impl` definition - impl Uto5 for (InsideMain,) {} - //~^ WARN non-local `impl` definition - impl Uto5 for fn(InsideMain) -> () {} - //~^ WARN non-local `impl` definition - impl Uto5 for fn() -> InsideMain {} - //~^ WARN non-local `impl` definition - - impl Debug for InsideMain { - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } - } - - impl InsideMain { - fn foo() {} - } - - fn inside_inside() { - impl Display for InsideMain { - //~^ WARN non-local `impl` definition - fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() - } - } - - impl InsideMain { - //~^ WARN non-local `impl` definition - fn bar() { - #[macro_export] - macro_rules! m2 { () => { } }; - //~^ WARN non-local `macro_rules!` definition - } - } - } - - trait Uto6 {} - impl dyn Uto6 {} - impl Uto5 for dyn Uto6 {} - - impl<T: Uto6> Uto3 for Vec<T> { } - //~^ WARN non-local `impl` definition -} - -trait Uto7 {} -trait Uto8 {} - -fn bad() { - struct Local; - impl Uto7 for Test where Local: std::any::Any {} - //~^ WARN non-local `impl` definition - - impl<T> Uto8 for T {} - //~^ WARN non-local `impl` definition -} - -trait Uto9 {} -trait Uto10 {} -const _: u32 = { - let _a = || { - impl Uto9 for Test {} - //~^ WARN non-local `impl` definition - - 1 - }; - - type A = [u32; { - impl Uto10 for Test {} - //~^ WARN non-local `impl` definition - - 1 - }]; - - 1 -}; - -struct UwU<T>(T); - -fn fun() { - #[derive(Debug)] - struct OwO; - impl Default for UwU<OwO> { - //~^ WARN non-local `impl` definition - fn default() -> Self { - UwU(OwO) - } - } -} - -struct Cat; - -fn meow() { - impl From<Cat> for () { - fn from(_: Cat) -> () { - todo!() - } - } - - #[derive(Debug)] - struct Cat; - impl AsRef<Cat> for () { - //~^ WARN non-local `impl` definition - fn as_ref(&self) -> &Cat { &Cat } - } -} - -struct G; - -fn fun2() { - #[derive(Debug, Default)] - struct B; - impl PartialEq<B> for G { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &B) -> bool { - true - } - } -} - -fn side_effects() { - dbg!(().as_ref()); // prints `Cat` - dbg!(UwU::default().0); - let _ = G::eq(&G, dbg!(&<_>::default())); -} - -struct Dog; - -fn woof() { - impl PartialEq<Dog> for &Dog { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &Dog) -> bool { - todo!() - } - } - - impl PartialEq<()> for Dog { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &()) -> bool { - todo!() - } - } - - impl PartialEq<()> for &Dog { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &()) -> bool { - todo!() - } - } - - impl PartialEq<Dog> for () { - //~^ WARN non-local `impl` definition - fn eq(&self, _: &Dog) -> bool { - todo!() - } - } - - struct Test; - impl PartialEq<Dog> for Test { - fn eq(&self, _: &Dog) -> bool { - todo!() - } - } -} - -struct Wrap<T>(T); - -impl Wrap<Wrap<Wrap<()>>> {} - -fn rawr() { - struct Lion; - - impl From<Wrap<Wrap<Lion>>> for () { - //~^ WARN non-local `impl` definition - fn from(_: Wrap<Wrap<Lion>>) -> Self { - todo!() - } - } - - impl From<()> for Wrap<Lion> { - //~^ WARN non-local `impl` definition - fn from(_: ()) -> Self { - todo!() - } - } - - #[derive(Debug)] - struct Elephant; - - impl From<Wrap<Wrap<Elephant>>> for () { - //~^ WARN non-local `impl` definition - fn from(_: Wrap<Wrap<Elephant>>) -> Self { - todo!() - } - } -} - -pub trait StillNonLocal {} - -impl StillNonLocal for &str {} - -fn only_global() { - struct Foo; - impl StillNonLocal for &Foo {} - //~^ WARN non-local `impl` definition -} - -struct GlobalSameFunction; - -fn same_function() { - struct Local1(GlobalSameFunction); - impl From<Local1> for GlobalSameFunction { - //~^ WARN non-local `impl` definition - fn from(x: Local1) -> GlobalSameFunction { - x.0 - } - } - - struct Local2(GlobalSameFunction); - impl From<Local2> for GlobalSameFunction { - //~^ WARN non-local `impl` definition - fn from(x: Local2) -> GlobalSameFunction { - x.0 - } - } -} - -struct GlobalDifferentFunction; - -fn diff_foo() { - struct Local(GlobalDifferentFunction); - - impl From<Local> for GlobalDifferentFunction { - // FIXME(Urgau): Should warn but doesn't since we currently consider - // the other impl to be "global", but that's not the case for the type-system - fn from(x: Local) -> GlobalDifferentFunction { - x.0 - } - } -} - -fn diff_bar() { - struct Local(GlobalDifferentFunction); - - impl From<Local> for GlobalDifferentFunction { - // FIXME(Urgau): Should warn but doesn't since we currently consider - // the other impl to be "global", but that's not the case for the type-system - fn from(x: Local) -> GlobalDifferentFunction { - x.0 - } - } -} - -macro_rules! m { - () => { - trait MacroTrait {} - struct OutsideStruct; - fn my_func() { - impl MacroTrait for OutsideStruct {} - //~^ WARN non-local `impl` definition - } - } -} - -m!(); - -struct CargoUpdate; - -non_local_macro::non_local_impl!(CargoUpdate); -//~^ WARN non-local `impl` definition - -non_local_macro::non_local_macro_rules!(my_macro); -//~^ WARN non-local `macro_rules!` definition - -fn bitflags() { - struct Flags; - - const _: () = { - impl Flags {} - }; -} - -// https://github.com/rust-lang/rust/issues/121621#issuecomment-1976826895 -fn commonly_reported() { - struct Local(u8); - impl From<Local> for u8 { - fn from(x: Local) -> u8 { - x.0 - } - } -} - -// https://github.com/rust-lang/rust/issues/121621#issue-2153187542 -pub trait Serde {} - -impl Serde for &[u8] {} -impl Serde for &str {} - -fn serde() { - struct Thing; - impl Serde for &Thing {} -} diff --git a/tests/ui/lint/non_local_definitions.stderr b/tests/ui/lint/non_local_definitions.stderr deleted file mode 100644 index 8ae04f2c2e8..00000000000 --- a/tests/ui/lint/non_local_definitions.stderr +++ /dev/null @@ -1,705 +0,0 @@ -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:36:5 - | -LL | const Z: () = { - | - help: use a const-anon item to suppress this lint: `_` -... -LL | impl Uto for &Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant `Z` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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: `#[warn(non_local_definitions)]` on by default - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:46:5 - | -LL | impl Uto for *mut Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:54:9 - | -LL | impl Uto for Test {} - | ^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:63:5 - | -LL | impl Uto2 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current static `A` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:71:5 - | -LL | impl Uto3 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant `B` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:75:5 - | -LL | macro_rules! m0 { () => { } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `B` - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = 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> - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:87:5 - | -LL | macro_rules! m { () => { } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current function `main` - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:90:5 - | -LL | / impl Test { -LL | | -LL | | fn foo() {} -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:96:9 - | -LL | / impl Test { -LL | | -LL | | fn bar() {} -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:105:9 - | -LL | / impl Test { -LL | | -LL | | fn hoo() {} -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current inline constant `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:114:9 - | -LL | / impl Test { -LL | | -LL | | fn foo2() {} -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current constant `_` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:122:5 - | -LL | / impl Display for Test { -LL | | -LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:129:5 - | -LL | impl dyn Uto5 {} - | ^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:132:5 - | -LL | impl<T: Uto5> Uto5 for Vec<T> { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:135:5 - | -LL | impl Uto5 for &dyn Uto5 {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:138:5 - | -LL | impl Uto5 for *mut Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:141:5 - | -LL | impl Uto5 for *mut [Test] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:144:5 - | -LL | impl Uto5 for [Test; 8] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:147:5 - | -LL | impl Uto5 for (Test,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:150:5 - | -LL | impl Uto5 for fn(Test) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:153:5 - | -LL | impl Uto5 for fn() -> Test {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:157:9 - | -LL | impl Uto5 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:164:9 - | -LL | impl Uto5 for &Test {} - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:171:9 - | -LL | impl Uto5 for &(Test,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:178:9 - | -LL | impl Uto5 for &(Test,Test) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:186:5 - | -LL | impl Uto5 for *mut InsideMain {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:188:5 - | -LL | impl Uto5 for *mut [InsideMain] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:190:5 - | -LL | impl Uto5 for [InsideMain; 8] {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:192:5 - | -LL | impl Uto5 for (InsideMain,) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:194:5 - | -LL | impl Uto5 for fn(InsideMain) -> () {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:196:5 - | -LL | impl Uto5 for fn() -> InsideMain {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:210:9 - | -LL | / impl Display for InsideMain { -LL | | -LL | | fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { -LL | | todo!() -LL | | } -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:217:9 - | -LL | / impl InsideMain { -LL | | -LL | | fn bar() { -LL | | #[macro_export] -... | -LL | | } -LL | | } - | |_________^ - | - = help: move this `impl` block outside the of the current function `inside_inside` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:221:17 - | -LL | macro_rules! m2 { () => { } }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current associated function `bar` and up 3 bodies - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:231:5 - | -LL | impl<T: Uto6> Uto3 for Vec<T> { } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `main` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:240:5 - | -LL | impl Uto7 for Test where Local: std::any::Any {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:243:5 - | -LL | impl<T> Uto8 for T {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `bad` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:251:9 - | -LL | impl Uto9 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current closure `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:258:9 - | -LL | impl Uto10 for Test {} - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant expression `<unnameable>` and up 2 bodies - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:272:5 - | -LL | / impl Default for UwU<OwO> { -LL | | -LL | | fn default() -> Self { -LL | | UwU(OwO) -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `fun` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:291:5 - | -LL | / impl AsRef<Cat> for () { -LL | | -LL | | fn as_ref(&self) -> &Cat { &Cat } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `meow` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:302:5 - | -LL | / impl PartialEq<B> for G { -LL | | -LL | | fn eq(&self, _: &B) -> bool { -LL | | true -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `fun2` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:319:5 - | -LL | / impl PartialEq<Dog> for &Dog { -LL | | -LL | | fn eq(&self, _: &Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:326:5 - | -LL | / impl PartialEq<()> for Dog { -LL | | -LL | | fn eq(&self, _: &()) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:333:5 - | -LL | / impl PartialEq<()> for &Dog { -LL | | -LL | | fn eq(&self, _: &()) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:340:5 - | -LL | / impl PartialEq<Dog> for () { -LL | | -LL | | fn eq(&self, _: &Dog) -> bool { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `woof` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:362:5 - | -LL | / impl From<Wrap<Wrap<Lion>>> for () { -LL | | -LL | | fn from(_: Wrap<Wrap<Lion>>) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:369:5 - | -LL | / impl From<()> for Wrap<Lion> { -LL | | -LL | | fn from(_: ()) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:379:5 - | -LL | / impl From<Wrap<Wrap<Elephant>>> for () { -LL | | -LL | | fn from(_: Wrap<Wrap<Elephant>>) -> Self { -LL | | todo!() -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `rawr` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:393:5 - | -LL | impl StillNonLocal for &Foo {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current function `only_global` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:401:5 - | -LL | / impl From<Local1> for GlobalSameFunction { -LL | | -LL | | fn from(x: Local1) -> GlobalSameFunction { -LL | | x.0 -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `same_function` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:409:5 - | -LL | / impl From<Local2> for GlobalSameFunction { -LL | | -LL | | fn from(x: Local2) -> GlobalSameFunction { -LL | | x.0 -LL | | } -LL | | } - | |_____^ - | - = help: move this `impl` block outside the of the current function `same_function` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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> - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:448:13 - | -LL | impl MacroTrait for OutsideStruct {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... -LL | m!(); - | ---- in this macro invocation - | - = help: move this `impl` block outside the of the current function `my_func` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: non-local `impl` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:458:1 - | -LL | non_local_macro::non_local_impl!(CargoUpdate); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: move this `impl` block outside the of the current constant `_IMPL_DEBUG` - = note: an `impl` definition is non-local if it is nested inside an item and may impact type checking outside of that item. This can be the case if neither the trait or the self type are at the same nesting level as the `impl` - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module and anon-const at the same nesting as the trait or type - = 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 macro `non_local_macro::non_local_impl` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` - = note: this warning originates in the macro `non_local_macro::non_local_impl` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: non-local `macro_rules!` definition, they should be avoided as they go against expectation - --> $DIR/non_local_definitions.rs:461:1 - | -LL | non_local_macro::non_local_macro_rules!(my_macro); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: remove the `#[macro_export]` or move this `macro_rules!` outside the of the current constant `_MACRO_EXPORT` - = note: a `macro_rules!` definition is non-local if it is nested inside an item and has a `#[macro_export]` attribute - = note: one exception to the rule are anon-const (`const _: () = { ... }`) at top-level module - = 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 macro `non_local_macro::non_local_macro_rules` may come from an old version of the `non_local_macro` crate, try updating your dependency with `cargo update -p non_local_macro` - = note: this warning originates in the macro `non_local_macro::non_local_macro_rules` (in Nightly builds, run with -Z macro-backtrace for more info) - -warning: 55 warnings emitted - diff --git a/tests/ui/lint/unused_braces_macro.rs b/tests/ui/lint/unused_braces_macro.rs index d0b42a12ff5..f9da4ed4e49 100644 --- a/tests/ui/lint/unused_braces_macro.rs +++ b/tests/ui/lint/unused_braces_macro.rs @@ -2,5 +2,5 @@ pub fn foo<const BAR: bool> () {} fn main() { - foo::<{cfg!(feature = "foo")}>(); + foo::<{cfg!(FALSE)}>(); } diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs index 57ba0d3bf56..83290790766 100644 --- a/tests/ui/macros/macro-attributes.rs +++ b/tests/ui/macros/macro-attributes.rs @@ -9,7 +9,7 @@ macro_rules! compiles_fine { // check that the attributes are recognised by requiring this // to be removed to avoid a compile error - #[cfg(always_remove)] + #[cfg(FALSE)] static MISTYPED: () = "foo"; } } diff --git a/tests/ui/macros/macro-error.rs b/tests/ui/macros/macro-error.rs index 59ed79e91f0..4984b92911e 100644 --- a/tests/ui/macros/macro-error.rs +++ b/tests/ui/macros/macro-error.rs @@ -5,5 +5,5 @@ macro_rules! foo { fn main() { foo!(0); // Check that we report errors at macro definition, not expansion. - let _: cfg!(foo) = (); //~ ERROR non-type macro in type position + let _: cfg!(FALSE) = (); //~ ERROR non-type macro in type position } diff --git a/tests/ui/macros/macro-error.stderr b/tests/ui/macros/macro-error.stderr index 2539a6d5156..fcf8d922d65 100644 --- a/tests/ui/macros/macro-error.stderr +++ b/tests/ui/macros/macro-error.stderr @@ -7,8 +7,8 @@ LL | ($a:expr) => a; error: non-type macro in type position: cfg --> $DIR/macro-error.rs:8:12 | -LL | let _: cfg!(foo) = (); - | ^^^^^^^^^ +LL | let _: cfg!(FALSE) = (); + | ^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs index a8cda23075b..6dbfce21359 100644 --- a/tests/ui/macros/macro-inner-attributes.rs +++ b/tests/ui/macros/macro-inner-attributes.rs @@ -5,11 +5,11 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #![$a] $i }); } test!(a, - #[cfg(qux)], + #[cfg(FALSE)], pub fn bar() { }); test!(b, - #[cfg(not(qux))], + #[cfg(not(FALSE))], pub fn bar() { }); #[rustc_dummy] diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs index 0752f7e3153..8c79683f49a 100644 --- a/tests/ui/macros/macro-outer-attributes.rs +++ b/tests/ui/macros/macro-outer-attributes.rs @@ -5,11 +5,11 @@ macro_rules! test { ($nm:ident, $i:item) => (mod $nm { #[$a] $i }); } test!(a, - #[cfg(qux)], + #[cfg(FALSE)], pub fn bar() { }); test!(b, - #[cfg(not(qux))], + #[cfg(not(FALSE))], pub fn bar() { }); // test1!(#[bar]) diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs index 3ff26025206..37188e45ad3 100644 --- a/tests/ui/macros/macro-with-attrs2.rs +++ b/tests/ui/macros/macro-with-attrs2.rs @@ -1,9 +1,9 @@ //@ run-pass -#[cfg(foo)] +#[cfg(FALSE)] macro_rules! foo { () => (1) } -#[cfg(not(foo))] +#[cfg(not(FALSE))] macro_rules! foo { () => (2) } pub fn main() { diff --git a/tests/ui/methods/call_method_unknown_pointee.rs b/tests/ui/methods/call_method_unknown_pointee.rs index 1643b6bfa18..a144e855ae3 100644 --- a/tests/ui/methods/call_method_unknown_pointee.rs +++ b/tests/ui/methods/call_method_unknown_pointee.rs @@ -8,10 +8,10 @@ fn main() { let ptr = &val as *const u32; unsafe { let _a: i32 = (ptr as *const _).read(); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + //~^ ERROR type annotations needed let b = ptr as *const _; + //~^ ERROR type annotations needed let _b: u8 = b.read(); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] let _c = (ptr as *const u8).read(); // we know the type here } @@ -19,10 +19,10 @@ fn main() { let ptr = &mut val as *mut u32; unsafe { let _a: i32 = (ptr as *mut _).read(); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] + //~^ ERROR type annotations needed let b = ptr as *mut _; + //~^ ERROR type annotations needed b.write(10); - //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699] (ptr as *mut i32).write(1000); // we know the type here } } diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr index 84ecf046e7a..9d0f38cf6b5 100644 --- a/tests/ui/methods/call_method_unknown_pointee.stderr +++ b/tests/ui/methods/call_method_unknown_pointee.stderr @@ -1,27 +1,49 @@ -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type +error[E0282]: type annotations needed --> $DIR/call_method_unknown_pointee.rs:10:41 | LL | let _a: i32 = (ptr as *const _).read(); | ^^^^ + | | + | cannot infer type + | cannot call a method on a raw pointer with an unknown pointee type -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type - --> $DIR/call_method_unknown_pointee.rs:13:24 +error[E0282]: type annotations needed for `*const _` + --> $DIR/call_method_unknown_pointee.rs:12:13 | +LL | let b = ptr as *const _; + | ^ +LL | LL | let _b: u8 = b.read(); - | ^^^^ + | ---- cannot call a method on a raw pointer with an unknown pointee type + | +help: consider giving `b` an explicit type, where the placeholders `_` are specified + | +LL | let b: *const _ = ptr as *const _; + | ++++++++++ -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type +error[E0282]: type annotations needed --> $DIR/call_method_unknown_pointee.rs:21:39 | LL | let _a: i32 = (ptr as *mut _).read(); | ^^^^ + | | + | cannot infer type + | cannot call a method on a raw pointer with an unknown pointee type -error[E0699]: cannot call a method on a raw pointer with an unknown pointee type - --> $DIR/call_method_unknown_pointee.rs:24:11 +error[E0282]: type annotations needed for `*mut _` + --> $DIR/call_method_unknown_pointee.rs:23:13 | +LL | let b = ptr as *mut _; + | ^ +LL | LL | b.write(10); - | ^^^^^ + | ----- cannot call a method on a raw pointer with an unknown pointee type + | +help: consider giving `b` an explicit type, where the placeholders `_` are specified + | +LL | let b: *mut _ = ptr as *mut _; + | ++++++++ error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0699`. +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/issues/auxiliary/issue-13872-1.rs b/tests/ui/modules/auxiliary/issue-13872-1.rs index fa9258834c7..fa9258834c7 100644 --- a/tests/ui/issues/auxiliary/issue-13872-1.rs +++ b/tests/ui/modules/auxiliary/issue-13872-1.rs diff --git a/tests/ui/issues/auxiliary/issue-13872-2.rs b/tests/ui/modules/auxiliary/issue-13872-2.rs index 8c64f16e3f9..8c64f16e3f9 100644 --- a/tests/ui/issues/auxiliary/issue-13872-2.rs +++ b/tests/ui/modules/auxiliary/issue-13872-2.rs diff --git a/tests/ui/issues/auxiliary/issue-13872-3.rs b/tests/ui/modules/auxiliary/issue-13872-3.rs index d31d52eb847..d31d52eb847 100644 --- a/tests/ui/issues/auxiliary/issue-13872-3.rs +++ b/tests/ui/modules/auxiliary/issue-13872-3.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs b/tests/ui/modules/auxiliary/issue-1920.rs index 1548cb99563..1548cb99563 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/auxiliary/issue-1920.rs +++ b/tests/ui/modules/auxiliary/issue-1920.rs diff --git a/tests/ui/issues/issue-13872.rs b/tests/ui/modules/issue-13872.rs index 5589d2d4f68..5589d2d4f68 100644 --- a/tests/ui/issues/issue-13872.rs +++ b/tests/ui/modules/issue-13872.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs b/tests/ui/modules/issue-1920-1.rs index 763d07db2cd..763d07db2cd 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.rs +++ b/tests/ui/modules/issue-1920-1.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr b/tests/ui/modules/issue-1920-1.stderr index b7c7da00672..b7c7da00672 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-1.stderr +++ b/tests/ui/modules/issue-1920-1.stderr diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs b/tests/ui/modules/issue-1920-2.rs index b5a90b2c8e8..b5a90b2c8e8 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.rs +++ b/tests/ui/modules/issue-1920-2.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr b/tests/ui/modules/issue-1920-2.stderr index 844cb0ff199..844cb0ff199 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-2.stderr +++ b/tests/ui/modules/issue-1920-2.stderr diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs b/tests/ui/modules/issue-1920-3.rs index 372c8b1511c..372c8b1511c 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.rs +++ b/tests/ui/modules/issue-1920-3.rs diff --git a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr b/tests/ui/modules/issue-1920-3.stderr index 525ca4685bb..525ca4685bb 100644 --- a/tests/ui/issues/issue-1920-absolute-paths/issue-1920-3.stderr +++ b/tests/ui/modules/issue-1920-3.stderr diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/nested-cfg-attrs.rs index c988d423373..0af28fc3d8e 100644 --- a/tests/ui/nested-cfg-attrs.rs +++ b/tests/ui/nested-cfg-attrs.rs @@ -1,4 +1,4 @@ -#[cfg_attr(all(), cfg_attr(all(), cfg(foo)))] +#[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))] fn f() {} fn main() { f() } //~ ERROR cannot find function `f` in this scope diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs b/tests/ui/nll/issue-40510-1.rs index ca53dcd9b41..ca53dcd9b41 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.rs +++ b/tests/ui/nll/issue-40510-1.rs diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr b/tests/ui/nll/issue-40510-1.stderr index 81fed1305cb..81fed1305cb 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-1.stderr +++ b/tests/ui/nll/issue-40510-1.stderr diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs b/tests/ui/nll/issue-40510-2.rs index 9ce54862265..9ce54862265 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-2.rs +++ b/tests/ui/nll/issue-40510-2.rs diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs b/tests/ui/nll/issue-40510-3.rs index 181263adcbf..181263adcbf 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.rs +++ b/tests/ui/nll/issue-40510-3.rs diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr b/tests/ui/nll/issue-40510-3.stderr index 43e8a73b819..43e8a73b819 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-3.stderr +++ b/tests/ui/nll/issue-40510-3.stderr diff --git a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs b/tests/ui/nll/issue-40510-4.rs index 771502894f1..771502894f1 100644 --- a/tests/ui/issues/issue-40510-captured-variable-return/issue-40510-4.rs +++ b/tests/ui/nll/issue-40510-4.rs diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed index aee05f5e512..4f5310082e1 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.fixed @@ -2,8 +2,6 @@ //@[old] edition:2015 //@[new] edition:2021 //@[new] run-rustfix -// FIXME: the test suite tries to create a crate called `bare_trait_dont_suggest_dyn.new` -#![crate_name="bare_trait_dont_suggest_dyn"] #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> impl Ord { //~^ ERROR the trait `Ord` cannot be made into an object diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr index 52db31d620c..efddab6dff6 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.new.stderr @@ -1,5 +1,5 @@ error[E0038]: the trait `Ord` cannot be made into an object - --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33 + --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33 | LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ `Ord` cannot be made into an object diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr index f795e910d21..0545a1afcc1 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr @@ -1,5 +1,5 @@ error: trait objects without an explicit `dyn` are deprecated - --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33 + --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33 | LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ @@ -7,7 +7,7 @@ LL | fn ord_prefer_dot(s: String) -> Ord { = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html> note: the lint level is defined here - --> $DIR/bare-trait-dont-suggest-dyn.rs:7:9 + --> $DIR/bare-trait-dont-suggest-dyn.rs:5:9 | LL | #![deny(bare_trait_objects)] | ^^^^^^^^^^^^^^^^^^ @@ -17,7 +17,7 @@ LL | fn ord_prefer_dot(s: String) -> dyn Ord { | +++ error[E0038]: the trait `Ord` cannot be made into an object - --> $DIR/bare-trait-dont-suggest-dyn.rs:8:33 + --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33 | LL | fn ord_prefer_dot(s: String) -> Ord { | ^^^ `Ord` cannot be made into an object diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs index e927b510b9d..cb5a305eab0 100644 --- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs +++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.rs @@ -2,8 +2,6 @@ //@[old] edition:2015 //@[new] edition:2021 //@[new] run-rustfix -// FIXME: the test suite tries to create a crate called `bare_trait_dont_suggest_dyn.new` -#![crate_name="bare_trait_dont_suggest_dyn"] #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> Ord { //~^ ERROR the trait `Ord` cannot be made into an object diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr index 82b61e43f44..23b863568bc 100644 --- a/tests/ui/panics/default-backtrace-ice.stderr +++ b/tests/ui/panics/default-backtrace-ice.stderr @@ -20,6 +20,8 @@ error: the compiler unexpectedly panicked. this is a bug. + + query stack during panic: #0 [resolver_for_lowering_raw] getting the resolver for lowering end of query stack diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs index d97f24a3d29..33671df9492 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs @@ -1,9 +1,9 @@ #![feature(stmt_expr_attributes)] fn foo() -> String { - #[cfg(feature = "validation")] + #[cfg(FALSE)] [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() //~ ERROR expected `;`, found `#` - #[cfg(not(feature = "validation"))] + #[cfg(not(FALSE))] String::new() } diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr index a71253a5e42..6266718162f 100644 --- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr +++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr @@ -1,11 +1,11 @@ error: expected `;`, found `#` --> $DIR/multiple-tail-expr-behind-cfg.rs:5:64 | -LL | #[cfg(feature = "validation")] - | ------------------------------ only `;` terminated statements or tail expressions are allowed after this attribute +LL | #[cfg(FALSE)] + | ------------- only `;` terminated statements or tail expressions are allowed after this attribute LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() | ^ expected `;` here -LL | #[cfg(not(feature = "validation"))] +LL | #[cfg(not(FALSE))] | - unexpected token | help: add `;` here @@ -18,9 +18,9 @@ LL | { [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() } | + + help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)` | -LL ~ if cfg!(feature = "validation") { +LL ~ if cfg!(FALSE) { LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() -LL ~ } else if cfg!(not(feature = "validation")) { +LL ~ } else if cfg!(not(FALSE)) { LL ~ String::new() LL + } | diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs index ad9e7ad707b..e2a62922bcc 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs @@ -5,7 +5,7 @@ macro_rules! the_macro { #[cfg()] $foo //~ ERROR expected `;`, found `#` - #[cfg(bar)] + #[cfg(FALSE)] $bar }; } diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr index 7b9b8319674..fa4409f73fa 100644 --- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr +++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr @@ -6,7 +6,7 @@ LL | #[cfg()] LL | $foo | ^ expected `;` here LL | -LL | #[cfg(bar)] +LL | #[cfg(FALSE)] | - unexpected token ... LL | the_macro!( (); (); ); diff --git a/tests/ui/parser/issues/issue-103381.fixed b/tests/ui/parser/issues/issue-103381.fixed index 9b63bf206a0..87c308789a1 100644 --- a/tests/ui/parser/issues/issue-103381.fixed +++ b/tests/ui/parser/issues/issue-103381.fixed @@ -37,21 +37,6 @@ fn should_ok_3() { if true && if true { true } else { false } {} } -fn shoule_match_ok() { - #[cfg(feature = "full")] - { - let a = 1; - let b = 2; - if match a { - 1 if b == 1 => true, - _ => false, - } && if a > 1 { true } else { false } - { - true - } - } -} - fn should_ok_in_nested() { if true && if true { true } else { false } { true } else { false }; } diff --git a/tests/ui/parser/issues/issue-103381.rs b/tests/ui/parser/issues/issue-103381.rs index a44a7410aaf..ccbc40e5d02 100644 --- a/tests/ui/parser/issues/issue-103381.rs +++ b/tests/ui/parser/issues/issue-103381.rs @@ -37,21 +37,6 @@ fn should_ok_3() { if true && if true { true } else { false } {} } -fn shoule_match_ok() { - #[cfg(feature = "full")] - { - let a = 1; - let b = 2; - if match a { - 1 if b == 1 => true, - _ => false, - } && if a > 1 { true } else { false } - { - true - } - } -} - fn should_ok_in_nested() { if true && if true { true } else { false } { true } else { false }; } diff --git a/tests/ui/precondition-checks/cfg-ub-checks-default.rs b/tests/ui/precondition-checks/cfg-ub-checks-default.rs new file mode 100644 index 00000000000..57a19523147 --- /dev/null +++ b/tests/ui/precondition-checks/cfg-ub-checks-default.rs @@ -0,0 +1,10 @@ +//@ run-pass +//@ revisions YES NO +//@ [YES] compile-flags: -Cdebug-assertions=yes +//@ [NO] compile-flags: -Cdebug-assertions=no + +#![feature(cfg_ub_checks)] + +fn main() { + assert_eq!(cfg!(ub_checks), cfg!(debug_assertions)); +} diff --git a/tests/ui/precondition-checks/cfg-ub-checks-no.rs b/tests/ui/precondition-checks/cfg-ub-checks-no.rs new file mode 100644 index 00000000000..73705a7e632 --- /dev/null +++ b/tests/ui/precondition-checks/cfg-ub-checks-no.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ compile-flags: -Zub-checks=no + +#![feature(cfg_ub_checks)] + +fn main() { + assert!(!cfg!(ub_checks)); + assert!(compiles_differently()); +} + +#[cfg(ub_checks)] +fn compiles_differently() -> bool { + false +} + +#[cfg(not(ub_checks))] +fn compiles_differently() -> bool { + true +} diff --git a/tests/ui/precondition-checks/cfg-ub-checks-yes.rs b/tests/ui/precondition-checks/cfg-ub-checks-yes.rs new file mode 100644 index 00000000000..410ab1fe4ec --- /dev/null +++ b/tests/ui/precondition-checks/cfg-ub-checks-yes.rs @@ -0,0 +1,19 @@ +//@ run-pass +//@ compile-flags: -Zub-checks=yes + +#![feature(cfg_ub_checks)] + +fn main() { + assert!(cfg!(ub_checks)); + assert!(compiles_differently()); +} + +#[cfg(ub_checks)] +fn compiles_differently() -> bool { + true +} + +#[cfg(not(ub_checks))] +fn compiles_differently() -> bool { + false +} diff --git a/tests/ui/precondition-checks/misaligned-slice.rs b/tests/ui/precondition-checks/misaligned-slice.rs index 52c149b594e..2963a0b5e63 100644 --- a/tests/ui/precondition-checks/misaligned-slice.rs +++ b/tests/ui/precondition-checks/misaligned-slice.rs @@ -1,5 +1,5 @@ //@ run-fail -//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes +//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts //@ ignore-debug diff --git a/tests/ui/precondition-checks/null-slice.rs b/tests/ui/precondition-checks/null-slice.rs index 61c7d467649..280960358b7 100644 --- a/tests/ui/precondition-checks/null-slice.rs +++ b/tests/ui/precondition-checks/null-slice.rs @@ -1,5 +1,5 @@ //@ run-fail -//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes +//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: unsafe precondition(s) violated: slice::from_raw_parts //@ ignore-debug diff --git a/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs b/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs index ba02c3da7b2..011e92183fa 100644 --- a/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs +++ b/tests/ui/precondition-checks/out-of-bounds-get-unchecked.rs @@ -1,5 +1,5 @@ //@ run-fail -//@ compile-flags: -Copt-level=3 -Cdebug-assertions=yes +//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes //@ error-pattern: slice::get_unchecked requires //@ ignore-debug diff --git a/tests/ui/privacy/unnameable_types.rs b/tests/ui/privacy/unnameable_types.rs index c6c5561c3c4..e82bfd0477f 100644 --- a/tests/ui/privacy/unnameable_types.rs +++ b/tests/ui/privacy/unnameable_types.rs @@ -1,4 +1,3 @@ -#![feature(type_privacy_lints)] #![deny(unnameable_types)] mod m { diff --git a/tests/ui/privacy/unnameable_types.stderr b/tests/ui/privacy/unnameable_types.stderr index d68a11c9728..a1bc60ef9c2 100644 --- a/tests/ui/privacy/unnameable_types.stderr +++ b/tests/ui/privacy/unnameable_types.stderr @@ -1,23 +1,23 @@ error: struct `PubStruct` is reachable but cannot be named - --> $DIR/unnameable_types.rs:5:5 + --> $DIR/unnameable_types.rs:4:5 | LL | pub struct PubStruct(pub i32); | ^^^^^^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` | note: the lint level is defined here - --> $DIR/unnameable_types.rs:2:9 + --> $DIR/unnameable_types.rs:1:9 | LL | #![deny(unnameable_types)] | ^^^^^^^^^^^^^^^^ error: enum `PubE` is reachable but cannot be named - --> $DIR/unnameable_types.rs:7:5 + --> $DIR/unnameable_types.rs:6:5 | LL | pub enum PubE { | ^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` error: trait `PubTr` is reachable but cannot be named - --> $DIR/unnameable_types.rs:11:5 + --> $DIR/unnameable_types.rs:10:5 | LL | pub trait PubTr { | ^^^^^^^^^^^^^^^ reachable at visibility `pub`, but can only be named at visibility `pub(crate)` diff --git a/tests/ui/proc-macro/modify-ast.rs b/tests/ui/proc-macro/modify-ast.rs index 86a7d6a7772..4c125c1c6e8 100644 --- a/tests/ui/proc-macro/modify-ast.rs +++ b/tests/ui/proc-macro/modify-ast.rs @@ -7,7 +7,7 @@ use modify_ast::*; #[derive(Foo)] pub struct MyStructc { - #[cfg_attr(my_cfg, foo)] + #[cfg_attr(FALSE, foo)] _a: i32, } diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs b/tests/ui/recursion/issue-23302-1.rs index 24e79dc5811..24e79dc5811 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.rs +++ b/tests/ui/recursion/issue-23302-1.rs diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr b/tests/ui/recursion/issue-23302-1.stderr index 234060ab5c8..234060ab5c8 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-1.stderr +++ b/tests/ui/recursion/issue-23302-1.stderr diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs b/tests/ui/recursion/issue-23302-2.rs index e89c7eab503..e89c7eab503 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.rs +++ b/tests/ui/recursion/issue-23302-2.rs diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr b/tests/ui/recursion/issue-23302-2.stderr index 9bd95239c83..9bd95239c83 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-2.stderr +++ b/tests/ui/recursion/issue-23302-2.stderr diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs b/tests/ui/recursion/issue-23302-3.rs index da75f330798..da75f330798 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.rs +++ b/tests/ui/recursion/issue-23302-3.rs diff --git a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr b/tests/ui/recursion/issue-23302-3.stderr index 8a152f58966..8a152f58966 100644 --- a/tests/ui/issues/issue-23302-enum-infinite-recursion/issue-23302-3.stderr +++ b/tests/ui/recursion/issue-23302-3.stderr diff --git a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs index f6a628e97f5..bef0d70c776 100644 --- a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs +++ b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.rs @@ -8,10 +8,10 @@ // // 'a : 'b -#![warn(unused_lifetimes)] +#![warn(redundant_lifetimes)] -fn test<'a,'b>(x: &'a i32) -> &'b i32 - where 'a: 'static //~ WARN unnecessary lifetime parameter `'a` +fn test<'a,'b>(x: &'a i32) -> &'b i32 //~ WARN unnecessary lifetime parameter `'a` + where 'a: 'static { x } diff --git a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr index 9f03a6553ba..d97cfd59f2b 100644 --- a/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr +++ b/tests/ui/regions/regions-free-region-outlives-static-outlives-free-region.stderr @@ -1,15 +1,15 @@ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:14:11 + --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:13:9 | -LL | where 'a: 'static - | ^^ +LL | fn test<'a,'b>(x: &'a i32) -> &'b i32 + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` note: the lint level is defined here --> $DIR/regions-free-region-outlives-static-outlives-free-region.rs:11:9 | -LL | #![warn(unused_lifetimes)] - | ^^^^^^^^^^^^^^^^ +LL | #![warn(redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ warning: 1 warning emitted diff --git a/tests/ui/regions/regions-static-bound-rpass.rs b/tests/ui/regions/regions-static-bound-rpass.rs index 27da42882f3..f4177f835b1 100644 --- a/tests/ui/regions/regions-static-bound-rpass.rs +++ b/tests/ui/regions/regions-static-bound-rpass.rs @@ -1,18 +1,19 @@ //@ run-pass -#![warn(unused_lifetimes)] +#![warn(redundant_lifetimes)] fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () - where 'a: 'static { t } //~^ WARN unnecessary lifetime parameter `'a` + where 'a: 'static { t } fn static_id<'a>(t: &'a ()) -> &'static () - where 'a: 'static { t } //~^ WARN unnecessary lifetime parameter `'a` + where 'a: 'static { t } fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () +//~^ WARN unnecessary lifetime parameter `'a` +//~| WARN unnecessary lifetime parameter `'b` where 'a: 'b, 'b: 'static { t } -//~^ WARN unnecessary lifetime parameter `'b` fn ref_id<'a>(t: &'a ()) -> &'a () where 'static: 'a { t } diff --git a/tests/ui/regions/regions-static-bound-rpass.stderr b/tests/ui/regions/regions-static-bound-rpass.stderr index f0f3a4c5261..4199ac7bb3d 100644 --- a/tests/ui/regions/regions-static-bound-rpass.stderr +++ b/tests/ui/regions/regions-static-bound-rpass.stderr @@ -1,31 +1,39 @@ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-static-bound-rpass.rs:6:11 + --> $DIR/regions-static-bound-rpass.rs:5:17 | -LL | where 'a: 'static { t } - | ^^ +LL | fn invariant_id<'a,'b>(t: &'b mut &'static ()) -> &'b mut &'a () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` note: the lint level is defined here --> $DIR/regions-static-bound-rpass.rs:3:9 | -LL | #![warn(unused_lifetimes)] - | ^^^^^^^^^^^^^^^^ +LL | #![warn(redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-static-bound-rpass.rs:10:11 + --> $DIR/regions-static-bound-rpass.rs:9:14 | -LL | where 'a: 'static { t } - | ^^ +LL | fn static_id<'a>(t: &'a ()) -> &'static () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` + +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound-rpass.rs:13:23 + | +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` warning: unnecessary lifetime parameter `'b` - --> $DIR/regions-static-bound-rpass.rs:14:19 + --> $DIR/regions-static-bound-rpass.rs:13:26 | -LL | where 'a: 'b, 'b: 'static { t } - | ^^ +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'b` + = note: you can use the `'static` lifetime directly, in place of `'b` -warning: 3 warnings emitted +warning: 4 warnings emitted diff --git a/tests/ui/regions/regions-static-bound.rs b/tests/ui/regions/regions-static-bound.rs index e7aa8795f01..32fa2536533 100644 --- a/tests/ui/regions/regions-static-bound.rs +++ b/tests/ui/regions/regions-static-bound.rs @@ -1,12 +1,13 @@ -#![warn(unused_lifetimes)] +#![warn(unused_lifetimes, redundant_lifetimes)] fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t } -//~^ WARN lifetime parameter `'b` never used -//~| WARN unnecessary lifetime parameter `'a` +//~^ WARN unnecessary lifetime parameter `'a` +//~| WARN lifetime parameter `'b` never used fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () +//~^ WARN unnecessary lifetime parameter `'a` +//~| WARN unnecessary lifetime parameter `'b` where 'a: 'b, 'b: 'static { t } -//~^ WARN unnecessary lifetime parameter `'b` fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { t diff --git a/tests/ui/regions/regions-static-bound.stderr b/tests/ui/regions/regions-static-bound.stderr index b314e9fe85d..48aa8f32329 100644 --- a/tests/ui/regions/regions-static-bound.stderr +++ b/tests/ui/regions/regions-static-bound.stderr @@ -9,27 +9,40 @@ LL | fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t } note: the lint level is defined here --> $DIR/regions-static-bound.rs:1:9 | -LL | #![warn(unused_lifetimes)] +LL | #![warn(unused_lifetimes, redundant_lifetimes)] | ^^^^^^^^^^^^^^^^ warning: unnecessary lifetime parameter `'a` - --> $DIR/regions-static-bound.rs:3:53 + --> $DIR/regions-static-bound.rs:3:14 | LL | fn static_id<'a,'b>(t: &'a ()) -> &'static () where 'a: 'static { t } - | ^^ + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'a` + = note: you can use the `'static` lifetime directly, in place of `'a` +note: the lint level is defined here + --> $DIR/regions-static-bound.rs:1:27 + | +LL | #![warn(unused_lifetimes, redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: unnecessary lifetime parameter `'a` + --> $DIR/regions-static-bound.rs:7:23 + | +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` warning: unnecessary lifetime parameter `'b` - --> $DIR/regions-static-bound.rs:8:19 + --> $DIR/regions-static-bound.rs:7:26 | -LL | where 'a: 'b, 'b: 'static { t } - | ^^ +LL | fn static_id_indirect<'a,'b>(t: &'a ()) -> &'static () + | ^^ | - = help: you can use the `'static` lifetime directly, in place of `'b` + = note: you can use the `'static` lifetime directly, in place of `'b` error: lifetime may not live long enough - --> $DIR/regions-static-bound.rs:12:5 + --> $DIR/regions-static-bound.rs:13:5 | LL | fn static_id_wrong_way<'a>(t: &'a ()) -> &'static () where 'static: 'a { | -- lifetime `'a` defined here @@ -37,7 +50,7 @@ LL | t | ^ returning this value requires that `'a` must outlive `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/regions-static-bound.rs:17:5 + --> $DIR/regions-static-bound.rs:18:5 | LL | fn error(u: &(), v: &()) { | - - let's call the lifetime of this reference `'1` @@ -50,7 +63,7 @@ LL | static_id(&u); | argument requires that `'1` must outlive `'static` error[E0521]: borrowed data escapes outside of function - --> $DIR/regions-static-bound.rs:19:5 + --> $DIR/regions-static-bound.rs:20:5 | LL | fn error(u: &(), v: &()) { | - - let's call the lifetime of this reference `'2` @@ -63,6 +76,6 @@ LL | static_id_indirect(&v); | `v` escapes the function body here | argument requires that `'2` must outlive `'static` -error: aborting due to 3 previous errors; 3 warnings emitted +error: aborting due to 3 previous errors; 4 warnings emitted For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/regions/transitively-redundant-lifetimes.rs b/tests/ui/regions/transitively-redundant-lifetimes.rs new file mode 100644 index 00000000000..9c29f66e54c --- /dev/null +++ b/tests/ui/regions/transitively-redundant-lifetimes.rs @@ -0,0 +1,20 @@ +#![deny(redundant_lifetimes)] + +fn a<'a, 'b>(x: &'a &'b &'a ()) {} //~ ERROR unnecessary lifetime parameter `'b` + +fn b<'a: 'b, 'b: 'a>() {} //~ ERROR unnecessary lifetime parameter `'b` + +struct Foo<T: 'static>(T); +fn c<'a>(_: Foo<&'a ()>) {} //~ ERROR unnecessary lifetime parameter `'a` + +struct Bar<'a>(&'a ()); +impl<'a> Bar<'a> { + fn d<'b: 'a>(&'b self) {} //~ ERROR unnecessary lifetime parameter `'b` +} + +fn ok(x: &'static &()) {} + +trait Tr<'a> {} +impl<'a: 'static> Tr<'a> for () {} //~ ERROR unnecessary lifetime parameter `'a` + +fn main() {} diff --git a/tests/ui/regions/transitively-redundant-lifetimes.stderr b/tests/ui/regions/transitively-redundant-lifetimes.stderr new file mode 100644 index 00000000000..2d8fc433b24 --- /dev/null +++ b/tests/ui/regions/transitively-redundant-lifetimes.stderr @@ -0,0 +1,47 @@ +error: unnecessary lifetime parameter `'b` + --> $DIR/transitively-redundant-lifetimes.rs:3:10 + | +LL | fn a<'a, 'b>(x: &'a &'b &'a ()) {} + | ^^ + | + = note: you can use the `'a` lifetime directly, in place of `'b` +note: the lint level is defined here + --> $DIR/transitively-redundant-lifetimes.rs:1:9 + | +LL | #![deny(redundant_lifetimes)] + | ^^^^^^^^^^^^^^^^^^^ + +error: unnecessary lifetime parameter `'b` + --> $DIR/transitively-redundant-lifetimes.rs:5:14 + | +LL | fn b<'a: 'b, 'b: 'a>() {} + | ^^ + | + = note: you can use the `'a` lifetime directly, in place of `'b` + +error: unnecessary lifetime parameter `'a` + --> $DIR/transitively-redundant-lifetimes.rs:8:6 + | +LL | fn c<'a>(_: Foo<&'a ()>) {} + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` + +error: unnecessary lifetime parameter `'a` + --> $DIR/transitively-redundant-lifetimes.rs:18:6 + | +LL | impl<'a: 'static> Tr<'a> for () {} + | ^^ + | + = note: you can use the `'static` lifetime directly, in place of `'a` + +error: unnecessary lifetime parameter `'b` + --> $DIR/transitively-redundant-lifetimes.rs:12:10 + | +LL | fn d<'b: 'a>(&'b self) {} + | ^^ + | + = note: you can use the `'a` lifetime directly, in place of `'b` + +error: aborting due to 5 previous errors + diff --git a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs index 2ae8eb9c56d..ef970ebd14b 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.rs @@ -6,7 +6,7 @@ //@ run-pass //@ compile-flags: -Z unleash-the-miri-inside-of-you -#![feature(core_intrinsics, const_caller_location)] +#![feature(core_intrinsics)] type L = &'static std::panic::Location<'static>; diff --git a/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs index 2c699437c83..c4e1f3ae48a 100644 --- a/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs +++ b/tests/ui/rfcs/rfc-2091-track-caller/const-caller-location.rs @@ -2,15 +2,13 @@ //@ revisions: default mir-opt //@[mir-opt] compile-flags: -Zmir-opt-level=4 -#![feature(const_caller_location)] - use std::panic::Location; const LOCATION: &Location = Location::caller(); const TRACKED: &Location = tracked(); #[track_caller] -const fn tracked() -> &'static Location <'static> { +const fn tracked() -> &'static Location<'static> { Location::caller() } @@ -26,18 +24,18 @@ const fn contained() -> &'static Location<'static> { fn main() { assert_eq!(LOCATION.file(), file!()); - assert_eq!(LOCATION.line(), 9); + assert_eq!(LOCATION.line(), 7); assert_eq!(LOCATION.column(), 29); assert_eq!(TRACKED.file(), file!()); - assert_eq!(TRACKED.line(), 11); + assert_eq!(TRACKED.line(), 9); assert_eq!(TRACKED.column(), 28); assert_eq!(NESTED.file(), file!()); - assert_eq!(NESTED.line(), 19); + assert_eq!(NESTED.line(), 17); assert_eq!(NESTED.column(), 5); assert_eq!(CONTAINED.file(), file!()); - assert_eq!(CONTAINED.line(), 24); + assert_eq!(CONTAINED.line(), 22); assert_eq!(CONTAINED.column(), 5); } diff --git a/tests/ui/sanitizer/cfg-kasan.rs b/tests/ui/sanitizer/cfg-kasan.rs index 394bf216581..491eaf3acc1 100644 --- a/tests/ui/sanitizer/cfg-kasan.rs +++ b/tests/ui/sanitizer/cfg-kasan.rs @@ -2,7 +2,7 @@ // the `#[cfg(sanitize = "address")]` attribute is configured. //@ check-pass -//@ compile-flags: -Zsanitizer=kernel-address --cfg kernel_address +//@ compile-flags: -Zsanitizer=kernel-address //@ revisions: aarch64 riscv64imac riscv64gc x86_64 //@[aarch64] compile-flags: --target aarch64-unknown-none //@[aarch64] needs-llvm-components: aarch64 @@ -22,5 +22,5 @@ trait Sized {} const _: fn() -> () = main; -#[cfg(all(sanitize = "address", kernel_address))] +#[cfg(sanitize = "address")] fn main() {} diff --git a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-fn-ptr.rs index 8f79de11748..505b4b8e7f0 100644 --- a/tests/ui/sanitizer/cfi-method-fn-ptr-cast.rs +++ b/tests/ui/sanitizer/cfi-fn-ptr.rs @@ -1,4 +1,4 @@ -// Verifies that casting a method to a function pointer works. +// Verifies that casting to a function pointer works. //@ revisions: cfi kcfi // FIXME(#122848) Remove only-linux once OSX CFI binaries work @@ -46,6 +46,8 @@ impl Trait1 for Type1 { fn foo(&self) {} } +fn foo<T>(_: &T) {} + fn main() { let type1 = Type1 {}; let f = <Type1 as Trait1>::foo; @@ -53,5 +55,7 @@ fn main() { // Check again with different optimization barriers S2 { f: <S as Foo>::foo }.foo(&S); // Check mismatched #[track_caller] - S2 { f: <S as Foo>::bar }.foo(&S) + S2 { f: <S as Foo>::bar }.foo(&S); + // Check non-method functions + S2 { f: foo }.foo(&S) } diff --git a/tests/ui/sanitizer/kcfi-mangling.rs b/tests/ui/sanitizer/kcfi-mangling.rs new file mode 100644 index 00000000000..fde7b5451b6 --- /dev/null +++ b/tests/ui/sanitizer/kcfi-mangling.rs @@ -0,0 +1,30 @@ +// Check KCFI extra mangling works correctly on v0 + +//@ needs-sanitizer-kcfi +//@ no-prefer-dynamic +//@ compile-flags: -C panic=abort -Zsanitizer=kcfi -C symbol-mangling-version=v0 +//@ build-pass + +trait Foo { + fn foo(&self); +} + +struct Bar; +impl Foo for Bar { + fn foo(&self) {} +} + +struct Baz; +impl Foo for Baz { + #[track_caller] + fn foo(&self) {} +} + +fn main() { + // Produces `ReifyShim(_, ReifyReason::FnPtr)` + let f: fn(&Bar) = Bar::foo; + f(&Bar); + // Produces `ReifyShim(_, ReifyReason::Vtable)` + let v: &dyn Foo = &Baz as _; + v.foo(); +} diff --git a/tests/ui/std/windows-bat-args.rs b/tests/ui/std/windows-bat-args.rs new file mode 100644 index 00000000000..a9b6252b78c --- /dev/null +++ b/tests/ui/std/windows-bat-args.rs @@ -0,0 +1,90 @@ +//@ only-windows +//@ run-pass +//@ run-flags:--parent-process + +use std::env; +use std::io::ErrorKind::{self, InvalidInput}; +use std::path::{Path, PathBuf}; +use std::process::Command; + +fn main() { + if env::args().nth(1).as_deref() == Some("--parent-process") { + parent(); + } else { + child(); + } +} + +fn child() { + if env::args().len() == 1 { + panic!("something went wrong :/"); + } + for arg in env::args().skip(1) { + print!("{arg}\0"); + } +} + +fn parent() { + let mut bat = PathBuf::from(file!()); + bat.set_file_name("windows-bat-args1.bat"); + let bat1 = String::from(bat.to_str().unwrap()); + bat.set_file_name("windows-bat-args2.bat"); + let bat2 = String::from(bat.to_str().unwrap()); + bat.set_file_name("windows-bat-args3.bat"); + let bat3 = String::from(bat.to_str().unwrap()); + let bat = [bat1.as_str(), bat2.as_str(), bat3.as_str()]; + + check_args(&bat, &["a", "b"]).unwrap(); + check_args(&bat, &["c is for cat", "d is for dog"]).unwrap(); + check_args(&bat, &["\"", " \""]).unwrap(); + check_args(&bat, &["\\", "\\"]).unwrap(); + check_args(&bat, &[">file.txt"]).unwrap(); + check_args(&bat, &["whoami.exe"]).unwrap(); + check_args(&bat, &["&a.exe"]).unwrap(); + check_args(&bat, &["&echo hello "]).unwrap(); + check_args(&bat, &["&echo hello", "&whoami", ">file.txt"]).unwrap(); + check_args(&bat, &["!TMP!"]).unwrap(); + check_args(&bat, &["key=value"]).unwrap(); + check_args(&bat, &["\"key=value\""]).unwrap(); + check_args(&bat, &["key = value"]).unwrap(); + check_args(&bat, &["key=[\"value\"]"]).unwrap(); + check_args(&bat, &["", "a=b"]).unwrap(); + check_args(&bat, &["key=\"foo bar\""]).unwrap(); + check_args(&bat, &["key=[\"my_value]"]).unwrap(); + check_args(&bat, &["key=[\"my_value\",\"other-value\"]"]).unwrap(); + check_args(&bat, &["key\\=value"]).unwrap(); + check_args(&bat, &["key=\"&whoami\""]).unwrap(); + check_args(&bat, &["key=\"value\"=5"]).unwrap(); + check_args(&bat, &["key=[\">file.txt\"]"]).unwrap(); + assert_eq!(check_args(&bat, &["\n"]), Err(InvalidInput)); + assert_eq!(check_args(&bat, &["\r"]), Err(InvalidInput)); + check_args(&bat, &["%hello"]).unwrap(); + check_args(&bat, &["%PATH%"]).unwrap(); + check_args(&bat, &["%%cd:~,%"]).unwrap(); + check_args(&bat, &["%PATH%PATH%"]).unwrap(); + check_args(&bat, &["\">file.txt"]).unwrap(); + check_args(&bat, &["abc\"&echo hello"]).unwrap(); + check_args(&bat, &["123\">file.txt"]).unwrap(); + check_args(&bat, &["\"&echo hello&whoami.exe"]).unwrap(); + check_args(&bat, &[r#"hello^"world"#, "hello &echo oh no >file.txt"]).unwrap(); +} + +// Check if the arguments roundtrip through a bat file and back into a Rust process. +// Our Rust process outptuts the arguments as null terminated strings. +#[track_caller] +fn check_args(bats: &[&str], args: &[&str]) -> Result<(), ErrorKind> { + for bat in bats { + let output = Command::new(&bat).args(args).output().map_err(|e| e.kind())?; + assert!(output.status.success()); + let child_args = String::from_utf8(output.stdout).unwrap(); + let mut child_args: Vec<&str> = + child_args.strip_suffix('\0').unwrap().split('\0').collect(); + // args3.bat can append spurious empty arguments, so trim them here. + child_args.truncate( + child_args.iter().rposition(|s| !s.is_empty()).unwrap_or(child_args.len() - 1) + 1, + ); + assert_eq!(&child_args, &args); + assert!(!Path::new("file.txt").exists()); + } + Ok(()) +} diff --git a/tests/ui/std/windows-bat-args1.bat b/tests/ui/std/windows-bat-args1.bat new file mode 100644 index 00000000000..edd36bd5530 --- /dev/null +++ b/tests/ui/std/windows-bat-args1.bat @@ -0,0 +1 @@ +@a.exe %* diff --git a/tests/ui/std/windows-bat-args2.bat b/tests/ui/std/windows-bat-args2.bat new file mode 100644 index 00000000000..8d5a7dd8a9e --- /dev/null +++ b/tests/ui/std/windows-bat-args2.bat @@ -0,0 +1 @@ +@a.exe %1 %2 %3 %4 %5 %6 %7 %8 %9 diff --git a/tests/ui/std/windows-bat-args3.bat b/tests/ui/std/windows-bat-args3.bat new file mode 100644 index 00000000000..7fe360a6d36 --- /dev/null +++ b/tests/ui/std/windows-bat-args3.bat @@ -0,0 +1 @@ +@a.exe "%~1" "%~2" "%~3" "%~4" "%~5" "%~6" "%~7" "%~8" "%~9" diff --git a/tests/ui/stmt_expr_attrs_no_feature.rs b/tests/ui/stmt_expr_attrs_no_feature.rs index 627c97da008..a160a9bb082 100644 --- a/tests/ui/stmt_expr_attrs_no_feature.rs +++ b/tests/ui/stmt_expr_attrs_no_feature.rs @@ -25,25 +25,25 @@ fn main() { // Check that cfg works right -#[cfg(unset)] +#[cfg(FALSE)] fn c() { #[rustc_dummy] 5; } -#[cfg(not(unset))] +#[cfg(not(FALSE))] fn j() { #[rustc_dummy] 5; } -#[cfg_attr(not(unset), cfg(unset))] +#[cfg_attr(not(FALSE), cfg(FALSE))] fn d() { #[rustc_dummy] 8; } -#[cfg_attr(not(unset), cfg(not(unset)))] +#[cfg_attr(not(FALSE), cfg(not(FALSE)))] fn i() { #[rustc_dummy] 8; @@ -57,25 +57,25 @@ macro_rules! item_mac { #[rustc_dummy] 42; - #[cfg(unset)] + #[cfg(FALSE)] fn f() { #[rustc_dummy] 5; } - #[cfg(not(unset))] + #[cfg(not(FALSE))] fn k() { #[rustc_dummy] 5; } - #[cfg_attr(not(unset), cfg(unset))] + #[cfg_attr(not(FALSE), cfg(FALSE))] fn g() { #[rustc_dummy] 8; } - #[cfg_attr(not(unset), cfg(not(unset)))] + #[cfg_attr(not(FALSE), cfg(not(FALSE)))] fn h() { #[rustc_dummy] 8; @@ -90,42 +90,42 @@ item_mac!(e); // check that the gate visitor works right: extern "C" { - #[cfg(unset)] + #[cfg(FALSE)] fn x(a: [u8; #[rustc_dummy] 5]); fn y(a: [u8; #[rustc_dummy] 5]); //~ ERROR attributes on expressions are experimental } struct Foo; impl Foo { - #[cfg(unset)] + #[cfg(FALSE)] const X: u8 = #[rustc_dummy] 5; const Y: u8 = #[rustc_dummy] 5; //~ ERROR attributes on expressions are experimental } trait Bar { - #[cfg(unset)] + #[cfg(FALSE)] const X: [u8; #[rustc_dummy] 5]; const Y: [u8; #[rustc_dummy] 5]; //~ ERROR attributes on expressions are experimental } struct Joyce { - #[cfg(unset)] + #[cfg(FALSE)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } struct Walky( - #[cfg(unset)] [u8; #[rustc_dummy] 5], + #[cfg(FALSE)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ); enum Mike { Happy( - #[cfg(unset)] [u8; #[rustc_dummy] 5], + #[cfg(FALSE)] [u8; #[rustc_dummy] 5], [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental ), Angry { - #[cfg(unset)] + #[cfg(FALSE)] field: [u8; #[rustc_dummy] 5], field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental } @@ -133,7 +133,7 @@ enum Mike { fn pat() { match 5 { - #[cfg(unset)] + #[cfg(FALSE)] 5 => #[rustc_dummy] (), 6 => #[rustc_dummy] (), //~ ERROR attributes on expressions are experimental _ => (), diff --git a/tests/ui/suggestions/option-to-bool.rs b/tests/ui/suggestions/option-to-bool.rs index 2a1823b15f5..bbc5d1d71cb 100644 --- a/tests/ui/suggestions/option-to-bool.rs +++ b/tests/ui/suggestions/option-to-bool.rs @@ -1,5 +1,3 @@ -#![cfg_attr(let_chains, feature(let_chains))] - fn foo(x: Option<i32>) { if true && x {} //~^ ERROR mismatched types diff --git a/tests/ui/suggestions/option-to-bool.stderr b/tests/ui/suggestions/option-to-bool.stderr index e16d829ca7a..ab97eae6c5c 100644 --- a/tests/ui/suggestions/option-to-bool.stderr +++ b/tests/ui/suggestions/option-to-bool.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/option-to-bool.rs:4:16 + --> $DIR/option-to-bool.rs:2:16 | LL | if true && x {} | ---- ^ expected `bool`, found `Option<i32>` diff --git a/tests/ui/symbol-names/basic.legacy.stderr b/tests/ui/symbol-names/basic.legacy.stderr index c1cbefac828..6ce0ae09195 100644 --- a/tests/ui/symbol-names/basic.legacy.stderr +++ b/tests/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h6fc0c8d27b1a289fE) +error: symbol-name(_ZN5basic4main17had874e876c8b1028E) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h6fc0c8d27b1a289f) +error: demangling(basic::main::had874e876c8b1028) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/tests/ui/symbol-names/issue-60925.legacy.stderr b/tests/ui/symbol-names/issue-60925.legacy.stderr index 7dd68e6e3a8..cc4eec470fb 100644 --- a/tests/ui/symbol-names/issue-60925.legacy.stderr +++ b/tests/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hab58a402db4ebf3aE) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17haf0d0ad2255e29c6E) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hab58a402db4ebf3a) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::haf0d0ad2255e29c6) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr index 54b1ea2764a..436f9ecf93d 100644 --- a/tests/ui/track-diagnostics/track.stderr +++ b/tests/ui/track-diagnostics/track.stderr @@ -30,6 +30,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md +note: please make sure that you have updated to the latest nightly + note: rustc $VERSION running on $TARGET note: compiler flags: ... -Z ui-testing ... -Z track-diagnostics diff --git a/tests/ui/issues/issue-2611-3.rs b/tests/ui/traits/issue-2611-3.rs index c95ebae33fa..c95ebae33fa 100644 --- a/tests/ui/issues/issue-2611-3.rs +++ b/tests/ui/traits/issue-2611-3.rs diff --git a/tests/ui/traits/make-sure-to-filter-projections-by-def-id.rs b/tests/ui/traits/make-sure-to-filter-projections-by-def-id.rs new file mode 100644 index 00000000000..27a3aad733c --- /dev/null +++ b/tests/ui/traits/make-sure-to-filter-projections-by-def-id.rs @@ -0,0 +1,38 @@ +//@ check-pass + +#![recursion_limit = "1024"] +// Really high recursion limit ^ + +// Test that ensures we're filtering projections by def id before matching +// them in `match_projection_projections`. + +use std::ops::{Add, Sub}; + +pub trait Scalar {} + +pub trait VectorCommon: Sized { + type T: Scalar; +} + +pub trait VectorOpsByValue<Rhs = Self, Output = Self>: + VectorCommon + Add<Rhs, Output = Output> + Sub<Rhs, Output = Output> +{ +} + +pub trait VectorView<'a>: + VectorOpsByValue<Self, Self::Owned> + VectorOpsByValue<Self::Owned, Self::Owned> +{ + type Owned; +} + +pub trait Vector: VectorOpsByValue<Self> + for<'a> VectorOpsByValue<Self::View<'a>> { + type View<'a>: VectorView<'a, T = Self::T, Owned = Self> + where + Self: 'a; +} + +pub trait MatrixCommon { + type V: Vector; +} + +fn main() {} diff --git a/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs b/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs new file mode 100644 index 00000000000..4e8c19d600d --- /dev/null +++ b/tests/ui/traits/pred-known-to-hold-modulo-regions-unsized-tail.rs @@ -0,0 +1,244 @@ +// This is a non-regression test for issues #108721 and its duplicate #123275 (hopefully, because +// the test is still convoluted and the ICE is fiddly). +// +// `pred_known_to_hold_modulo_regions` prevented "unexpected unsized tail" ICEs with warp/hyper but +// was unknowingly removed in #120463. + +//@ build-pass: the ICE happened in codegen + +use std::future::Future; +trait TryFuture: Future { + type Ok; +} +impl<F, T> TryFuture for F +where + F: ?Sized + Future<Output = Option<T>>, +{ + type Ok = T; +} +trait Executor {} +struct Exec {} +trait HttpBody { + type Data; +} +trait ConnStreamExec<F> {} +impl<F> ConnStreamExec<F> for Exec where H2Stream<F>: Send {} +impl<E, F> ConnStreamExec<F> for E where E: Executor {} +struct H2Stream<F> { + _fut: F, +} +trait NewSvcExec<S, E, W: Watcher<S, E>> { + fn execute_new_svc(&mut self, _fut: NewSvcTask<S, E, W>) { + unimplemented!() + } +} +impl<S, E, W> NewSvcExec<S, E, W> for Exec where W: Watcher<S, E> {} +trait Watcher<S, E> { + type Future; +} +struct NoopWatcher; +impl<S, E> Watcher<S, E> for NoopWatcher +where + S: HttpService, + E: ConnStreamExec<S::Future>, +{ + type Future = Option<<<S as HttpService>::ResBody as HttpBody>::Data>; +} +trait Service<Request> { + type Response; + type Future; +} +trait HttpService { + type ResBody: HttpBody; + type Future; +} +struct Body {} +impl HttpBody for Body { + type Data = String; +} +impl<S> HttpService for S +where + S: Service<(), Response = ()>, +{ + type ResBody = Body; + type Future = S::Future; +} +trait MakeServiceRef<Target> { + type ResBody; + type Service: HttpService<ResBody = Self::ResBody>; +} +impl<T, Target, S, F> MakeServiceRef<Target> for T +where + T: for<'a> Service<&'a Target, Response = S, Future = F>, + S: HttpService, +{ + type Service = S; + type ResBody = S::ResBody; +} +fn make_service_fn<F, Target, Ret>(_f: F) -> MakeServiceFn<F> +where + F: FnMut(&Target) -> Ret, + Ret: Future, +{ + unimplemented!() +} +struct MakeServiceFn<F> { + _func: F, +} +impl<'t, F, Ret, Target, Svc> Service<&'t Target> for MakeServiceFn<F> +where + F: FnMut(&Target) -> Ret, + Ret: Future<Output = Option<Svc>>, +{ + type Response = Svc; + type Future = Option<()>; +} +struct AddrIncoming {} +struct Server<I, S, E> { + _incoming: I, + _make_service: S, + _protocol: E, +} +impl<I, S, E, B> Server<I, S, E> +where + S: MakeServiceRef<(), ResBody = B>, + B: HttpBody, + E: ConnStreamExec<<S::Service as HttpService>::Future>, + E: NewSvcExec<S::Service, E, NoopWatcher>, +{ + fn serve(&mut self) { + let fut = NewSvcTask::new(); + self._protocol.execute_new_svc(fut); + } +} +fn serve<S>(_make_service: S) -> Server<AddrIncoming, S, Exec> { + unimplemented!() +} +struct NewSvcTask<S, E, W: Watcher<S, E>> { + _state: State<S, E, W>, +} +struct State<S, E, W: Watcher<S, E>> { + _fut: W::Future, +} +impl<S, E, W: Watcher<S, E>> NewSvcTask<S, E, W> { + fn new() -> Self { + unimplemented!() + } +} +trait Filter { + type Extract; + type Future; + fn map<F>(self, _fun: F) -> MapFilter<Self, F> + where + Self: Sized, + { + unimplemented!() + } + fn wrap_with<W>(self, _wrapper: W) -> W::Wrapped + where + Self: Sized, + W: Wrap<Self>, + { + unimplemented!() + } +} +fn service<F>(_filter: F) -> FilteredService<F> +where + F: Filter, +{ + unimplemented!() +} +struct FilteredService<F> { + _filter: F, +} +impl<F> Service<()> for FilteredService<F> +where + F: Filter, +{ + type Response = (); + type Future = FilteredFuture<F::Future>; +} +struct FilteredFuture<F> { + _fut: F, +} +struct MapFilter<T, F> { + _filter: T, + _func: F, +} +impl<T, F> Filter for MapFilter<T, F> +where + T: Filter, + F: Func<T::Extract>, +{ + type Extract = F::Output; + type Future = MapFilterFuture<T, F>; +} +struct MapFilterFuture<T: Filter, F> { + _extract: T::Future, + _func: F, +} +trait Wrap<F> { + type Wrapped; +} +fn make_filter_fn<F, U>(_func: F) -> FilterFn<F> +where + F: Fn() -> U, +{ + unimplemented!() +} +struct FilterFn<F> { + _func: F, +} +impl<F, U> Filter for FilterFn<F> +where + F: Fn() -> U, + U: TryFuture, + U::Ok: Send, +{ + type Extract = U::Ok; + type Future = Option<U>; +} +fn trace<F>(_func: F) -> Trace<F> +where + F: Fn(), +{ + unimplemented!() +} +struct Trace<F> { + _func: F, +} +impl<FN, F> Wrap<F> for Trace<FN> { + type Wrapped = WithTrace<FN, F>; +} +struct WithTrace<FN, F> { + _filter: F, + _trace: FN, +} +impl<FN, F> Filter for WithTrace<FN, F> +where + F: Filter, +{ + type Extract = (); + type Future = (F::Future, fn(F::Extract)); +} +trait Func<Args> { + type Output; +} +impl<F, R> Func<()> for F +where + F: Fn() -> R, +{ + type Output = R; +} +fn main() { + let make_service = make_service_fn(|_| { + let tracer = trace(|| unimplemented!()); + let filter = make_filter_fn(|| std::future::ready(Some(()))) + .map(|| "Hello, world") + .wrap_with(tracer); + let svc = service(filter); + std::future::ready(Some(svc)) + }); + let mut server = serve(make_service); + server.serve(); +} diff --git a/tests/ui/transmutability/arrays/huge-len.stderr b/tests/ui/transmutability/arrays/huge-len.stderr index 37160c5c959..3fc652f47c1 100644 --- a/tests/ui/transmutability/arrays/huge-len.stderr +++ b/tests/ui/transmutability/arrays/huge-len.stderr @@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `ExplicitlyPadded` --> $DIR/huge-len.rs:21:41 | LL | assert::is_maybe_transmutable::<(), ExplicitlyPadded>(); - | ^^^^^^^^^^^^^^^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | ^^^^^^^^^^^^^^^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 @@ -17,7 +17,7 @@ error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` --> $DIR/huge-len.rs:24:55 | LL | assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); - | ^^ values of the type `ExplicitlyPadded` are too big for the current architecture + | ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/huge-len.rs:8:14 diff --git a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr index e486928a445..b4cd70142c4 100644 --- a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -2,7 +2,7 @@ error[E0277]: `[String; 0]` cannot be safely transmuted into `()` --> $DIR/should_require_well_defined_layout.rs:25:52 | LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `[String; 0]` is not yet supported. + | ^^ analyzing the transmutability of `[String; 0]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -23,7 +23,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` --> $DIR/should_require_well_defined_layout.rs:26:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `[String; 0]` is not yet supported. + | ^^^^^^^^^ analyzing the transmutability of `[String; 0]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -44,7 +44,7 @@ error[E0277]: `[String; 1]` cannot be safely transmuted into `()` --> $DIR/should_require_well_defined_layout.rs:31:52 | LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `[String; 1]` is not yet supported. + | ^^ analyzing the transmutability of `[String; 1]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -65,7 +65,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` --> $DIR/should_require_well_defined_layout.rs:32:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `[String; 1]` is not yet supported. + | ^^^^^^^^^ analyzing the transmutability of `[String; 1]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -86,7 +86,7 @@ error[E0277]: `[String; 2]` cannot be safely transmuted into `()` --> $DIR/should_require_well_defined_layout.rs:37:52 | LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `[String; 2]` is not yet supported. + | ^^ analyzing the transmutability of `[String; 2]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 @@ -107,7 +107,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` --> $DIR/should_require_well_defined_layout.rs:38:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `[String; 2]` is not yet supported. + | ^^^^^^^^^ analyzing the transmutability of `[String; 2]` is not yet supported | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:12:14 diff --git a/tests/ui/transmutability/enums/niche_optimization.rs b/tests/ui/transmutability/enums/niche_optimization.rs new file mode 100644 index 00000000000..23f57ecad75 --- /dev/null +++ b/tests/ui/transmutability/enums/niche_optimization.rs @@ -0,0 +1,156 @@ +//@ check-pass +//! Checks that niche optimizations are encoded correctly. +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: true, + } + }> + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } +#[repr(u8)] enum V2 { V = 2 } +#[repr(u8)] enum V253 { V = 253 } +#[repr(u8)] enum V254 { V = 254 } +#[repr(u8)] enum V255 { V = 255 } + +fn bool() { + enum OptionLike { + A(bool), + B, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + + assert::is_transmutable::<bool, OptionLike>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V1, OptionLike>(); + assert::is_transmutable::<V2, OptionLike>(); +} + +fn one_niche() { + #[repr(u8)] + enum N1 { + S = 0, + E = 255 - 1, + } + + enum OptionLike { + A(N1), + B, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V254, OptionLike>(); + assert::is_transmutable::<V255, OptionLike>(); +} + +fn one_niche_alt() { + #[repr(u8)] + enum N1 { + S = 1, + E = 255 - 1, + } + + enum OptionLike { + A(N1), + B, + C, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V254, OptionLike>(); + assert::is_transmutable::<V255, OptionLike>(); +} + +fn two_niche() { + #[repr(u8)] + enum Niche { + S = 0, + E = 255 - 2, + } + + enum OptionLike { + A(Niche), + B, + C, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 1); + }; + + assert::is_transmutable::<OptionLike, u8>(); + assert::is_transmutable::<V0, OptionLike>(); + assert::is_transmutable::<V253, OptionLike>(); + assert::is_transmutable::<V254, OptionLike>(); + assert::is_transmutable::<V255, OptionLike>(); +} + +fn no_niche() { + use std::mem::MaybeUninit; + + #[repr(u8)] + enum Niche { + S = 0, + E = 255 - 1, + } + + enum OptionLike { + A(Niche), + B, + C, + } + + const _: () = { + assert!(std::mem::size_of::<OptionLike>() == 2); + }; + + #[repr(C)] + struct Pair<T, U>(T, U); + + assert::is_transmutable::<V0, Niche>(); + assert::is_transmutable::<V254, Niche>(); + assert::is_transmutable::<Pair<V0, Niche>, OptionLike>(); + assert::is_transmutable::<Pair<V1, MaybeUninit<u8>>, OptionLike>(); + assert::is_transmutable::<Pair<V2, MaybeUninit<u8>>, OptionLike>(); +} diff --git a/tests/ui/transmutability/enums/repr/padding_differences.rs b/tests/ui/transmutability/enums/repr/padding_differences.rs new file mode 100644 index 00000000000..d0e1502b5e2 --- /dev/null +++ b/tests/ui/transmutability/enums/repr/padding_differences.rs @@ -0,0 +1,80 @@ +//@ check-pass +//! Adapted from https://rust-lang.github.io/unsafe-code-guidelines/layout/enums.html#explicit-repr-annotation-without-c-compatibility +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +use std::mem::MaybeUninit; + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: false, + lifetimes: false, + safety: true, + validity: true, + } + }> + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } + +fn repr_u8() { + #[repr(u8)] + enum TwoCases { + A(u8, u16), // 0x00 INIT INIT INIT + B(u16), // 0x01 PADD INIT INIT + } + + const _: () = { + assert!(std::mem::size_of::<TwoCases>() == 4); + }; + + #[repr(C)] struct TwoCasesA(V0, u8, u8, u8); + #[repr(C)] struct TwoCasesB(V1, MaybeUninit<u8>, u8, u8); + + assert::is_transmutable::<TwoCasesA, TwoCases>(); + assert::is_transmutable::<TwoCasesB, TwoCases>(); + + assert::is_maybe_transmutable::<TwoCases, TwoCasesA>(); + assert::is_maybe_transmutable::<TwoCases, TwoCasesB>(); +} + +fn repr_c_u8() { + #[repr(C, u8)] + enum TwoCases { + A(u8, u16), // 0x00 PADD INIT PADD INIT INIT + B(u16), // 0x01 PADD INIT INIT PADD PADD + } + + const _: () = { + assert!(std::mem::size_of::<TwoCases>() == 6); + }; + + #[repr(C)] struct TwoCasesA(V0, MaybeUninit<u8>, u8, MaybeUninit<u8>, u8, u8); + #[repr(C)] struct TwoCasesB(V1, MaybeUninit<u8>, u8, u8, MaybeUninit<u8>, MaybeUninit<u8>); + + assert::is_transmutable::<TwoCasesA, TwoCases>(); + assert::is_transmutable::<TwoCasesB, TwoCases>(); + + assert::is_maybe_transmutable::<TwoCases, TwoCasesA>(); + assert::is_maybe_transmutable::<TwoCases, TwoCasesB>(); +} diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/enums/repr/should_handle_all.rs index 630e662b926..a8ec86fa40d 100644 --- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.rs +++ b/tests/ui/transmutability/enums/repr/should_handle_all.rs @@ -1,5 +1,4 @@ -//! An enum must have a well-defined layout to participate in a transmutation. - +//@ check-pass #![crate_type = "lib"] #![feature(repr128)] #![feature(transmutability)] @@ -21,23 +20,17 @@ mod assert { {} } -fn should_reject_repr_rust() { - fn void() { - enum repr_rust {} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted - } - +fn should_accept_repr_rust() { fn singleton() { enum repr_rust { V } - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn duplex() { enum repr_rust { A, B } - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } } @@ -116,7 +109,7 @@ fn should_accept_primitive_reprs() } } -fn should_accept_repr_C() { +fn should_accept_repr_c() { #[repr(C)] enum repr_c { V } assert::is_maybe_transmutable::<repr_c, ()>(); assert::is_maybe_transmutable::<i128, repr_c>(); diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr deleted file mode 100644 index 2a683de6a65..00000000000 --- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr +++ /dev/null @@ -1,135 +0,0 @@ -error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:27:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `void::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13: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]: `u128` cannot be safely transmuted into `void::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:28:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `void::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13: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]: `singleton::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:33:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13: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]: `u128` cannot be safely transmuted into `singleton::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:34:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `singleton::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13: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]: `duplex::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:39:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13: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]: `u128` cannot be safely transmuted into `duplex::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:40:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `duplex::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:13: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: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr index eeed8a62a2a..cabc7bcfef7 100644 --- a/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr +++ b/tests/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr @@ -8,7 +8,7 @@ error[E0277]: `Src` cannot be safely transmuted into `Dst` --> $DIR/unknown_src_field.rs:19:36 | LL | assert::is_transmutable::<Src, Dst>(); - | ^^^ `Dst` has an unknown layout + | ^^^ analyzing the transmutability of `Dst` is not yet supported | note: required by a bound in `is_transmutable` --> $DIR/unknown_src_field.rs:12:14 diff --git a/tests/ui/transmutability/maybeuninit.rs b/tests/ui/transmutability/maybeuninit.rs new file mode 100644 index 00000000000..77c3381c774 --- /dev/null +++ b/tests/ui/transmutability/maybeuninit.rs @@ -0,0 +1,43 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +use std::mem::MaybeUninit; + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + {} +} + +fn validity() { + // An initialized byte is a valid uninitialized byte. + assert::is_maybe_transmutable::<u8, MaybeUninit<u8>>(); + + // An uninitialized byte is never a valid initialized byte. + assert::is_maybe_transmutable::<MaybeUninit<u8>, u8>(); //~ ERROR: cannot be safely transmuted +} + +fn padding() { + #[repr(align(8))] + struct Align8; + + #[repr(u8)] + enum ImplicitlyPadded { + A(Align8), + } + + #[repr(u8)] + enum V0 { + V0 = 0, + } + + #[repr(C)] + struct ExplicitlyPadded(V0, MaybeUninit<[u8; 7]>); + + assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>(); + assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>(); +} diff --git a/tests/ui/transmutability/maybeuninit.stderr b/tests/ui/transmutability/maybeuninit.stderr new file mode 100644 index 00000000000..be7dcaf35ea --- /dev/null +++ b/tests/ui/transmutability/maybeuninit.stderr @@ -0,0 +1,18 @@ +error[E0277]: `MaybeUninit<u8>` cannot be safely transmuted into `u8` + --> $DIR/maybeuninit.rs:21:54 + | +LL | assert::is_maybe_transmutable::<MaybeUninit<u8>, u8>(); + | ^^ at least one value of `MaybeUninit<u8>` isn't a bit-valid value of `u8` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/maybeuninit.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/references/unsafecell.rs b/tests/ui/transmutability/references/unsafecell.rs new file mode 100644 index 00000000000..a8a1f969fb4 --- /dev/null +++ b/tests/ui/transmutability/references/unsafecell.rs @@ -0,0 +1,47 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +use std::cell::UnsafeCell; + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + {} +} + +fn value_to_value() { + // We accept value-to-value transmutations of `UnsafeCell`-containing types, + // because owning a value implies exclusive access. + assert::is_maybe_transmutable::<UnsafeCell<u8>, u8>(); + assert::is_maybe_transmutable::<u8, UnsafeCell<u8>>(); + assert::is_maybe_transmutable::<UnsafeCell<u8>, UnsafeCell<u8>>(); +} + +fn ref_to_ref() { + // We forbid `UnsafeCell`-containing ref-to-ref transmutations, because the + // two types may use different, incompatible synchronization strategies. + assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted + + assert::is_maybe_transmutable::<&'static UnsafeCell<u8>, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted +} + +fn mut_to_mut() { + // `UnsafeCell` does't matter for `&mut T` to `&mut U`, since exclusive + // borrows can't be used for shared access. + assert::is_maybe_transmutable::<&'static mut u8, &'static mut UnsafeCell<u8>>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static mut u8>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static mut UnsafeCell<u8>>(); +} + +fn mut_to_ref() { + // We don't care about `UnsafeCell` for transmutations in the form `&mut T + // -> &U`, because downgrading a `&mut T` to a `&U` deactivates `&mut T` for + // the lifetime of `&U`. + assert::is_maybe_transmutable::<&'static mut u8, &'static UnsafeCell<u8>>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static u8>(); + assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static UnsafeCell<u8>>(); +} diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr new file mode 100644 index 00000000000..651eb8ceb26 --- /dev/null +++ b/tests/ui/transmutability/references/unsafecell.stderr @@ -0,0 +1,33 @@ +error[E0277]: `&u8` cannot be safely transmuted into `&UnsafeCell<u8>` + --> $DIR/unsafecell.rs:27:50 + | +LL | assert::is_maybe_transmutable::<&'static u8, &'static UnsafeCell<u8>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/unsafecell.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: `&UnsafeCell<u8>` cannot be safely transmuted into `&UnsafeCell<u8>` + --> $DIR/unsafecell.rs:29:62 + | +LL | assert::is_maybe_transmutable::<&'static UnsafeCell<u8>, &'static UnsafeCell<u8>>(); + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `&'static UnsafeCell<u8>` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/unsafecell.rs:12:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, { Assume::SAFETY }> + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/structs/repr/should_handle_all.rs index 2e673601baf..52c24eecf12 100644 --- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.rs +++ b/tests/ui/transmutability/structs/repr/should_handle_all.rs @@ -1,3 +1,4 @@ +//@ check-pass //! A struct must have a well-defined layout to participate in a transmutation. #![crate_type = "lib"] @@ -20,47 +21,47 @@ mod assert { {} } -fn should_reject_repr_rust() +fn should_accept_repr_rust() { fn unit() { struct repr_rust; - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn tuple() { struct repr_rust(); - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn braces() { struct repr_rust{} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn aligned() { #[repr(align(1))] struct repr_rust{} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn packed() { #[repr(packed)] struct repr_rust{} - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } fn nested() { struct repr_rust; #[repr(C)] struct repr_c(repr_rust); - assert::is_maybe_transmutable::<repr_c, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_c>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_c, ()>(); + assert::is_maybe_transmutable::<u128, repr_c>(); } } -fn should_accept_repr_C() +fn should_accept_repr_c() { fn unit() { #[repr(C)] struct repr_c; diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr deleted file mode 100644 index 77788f72c21..00000000000 --- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr +++ /dev/null @@ -1,267 +0,0 @@ -error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:27:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:28:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::unit::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:33:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:34:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::tuple::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:39:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:40:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::braces::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `aligned::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:45:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `u128` cannot be safely transmuted into `aligned::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:46:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `aligned::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `packed::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:51:52 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `packed::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `u128` cannot be safely transmuted into `packed::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:52:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `packed::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `nested::repr_c` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:58:49 - | -LL | assert::is_maybe_transmutable::<repr_c, ()>(); - | ^^ analyzing the transmutability of `nested::repr_c` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `u128` cannot be safely transmuted into `nested::repr_c` - --> $DIR/should_require_well_defined_layout.rs:59:47 - | -LL | assert::is_maybe_transmutable::<u128, repr_c>(); - | ^^^^^^ analyzing the transmutability of `nested::repr_c` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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: aborting due to 12 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs index 4c285a616b3..64110753832 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.rs @@ -22,4 +22,5 @@ fn should_pad_explicitly_packed_field() { //~^ ERROR: recursive type assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); + //~^ ERROR: cannot be safely transmuted } diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index 7fb051f6625..ebfb5361143 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -15,7 +15,22 @@ error[E0391]: cycle detected when computing layout of `should_pad_explicitly_pac = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::BikeshedIntrinsicFrom<should_pad_explicitly_packed_field::ExplicitlyPadded, core::mem::transmutability::Assume { alignment: false, lifetimes: false, safety: false, validity: false }>` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information -error: aborting due to 2 previous errors +error[E0277]: `ExplicitlyPadded` cannot be safely transmuted into `()` + --> $DIR/transmute_infinitely_recursive_type.rs:24:55 + | +LL | assert::is_maybe_transmutable::<ExplicitlyPadded, ()>(); + | ^^ analyzing the transmutability of `ExplicitlyPadded` is not yet supported + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/transmute_infinitely_recursive_type.rs:14:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0072, E0391. +Some errors have detailed explanations: E0072, E0277, E0391. For more information about an error, try `rustc --explain E0072`. diff --git a/tests/ui/transmutability/transmute-padding-ice.rs b/tests/ui/transmutability/transmute-padding-ice.rs index 3f3f75bc086..f5935a0009e 100644 --- a/tests/ui/transmutability/transmute-padding-ice.rs +++ b/tests/ui/transmutability/transmute-padding-ice.rs @@ -1,7 +1,13 @@ +//@ check-pass +//! This UI test was introduced as check-fail by a buggy bug-fix for an ICE. In +//! fact, this transmutation should be valid. + #![crate_type = "lib"] #![feature(transmutability)] #![allow(dead_code)] +use std::mem::size_of; + mod assert { use std::mem::{Assume, BikeshedIntrinsicFrom}; @@ -22,6 +28,7 @@ fn test() { #[repr(C)] struct B(u8, u8); + assert_eq!(size_of::<A>(), size_of::<B>()); + assert::is_maybe_transmutable::<B, A>(); - //~^ ERROR cannot be safely transmuted } diff --git a/tests/ui/transmutability/transmute-padding-ice.stderr b/tests/ui/transmutability/transmute-padding-ice.stderr deleted file mode 100644 index 4c121d463c6..00000000000 --- a/tests/ui/transmutability/transmute-padding-ice.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0277]: `B` cannot be safely transmuted into `A` - --> $DIR/transmute-padding-ice.rs:25:40 - | -LL | assert::is_maybe_transmutable::<B, A>(); - | ^ the size of `B` is smaller than the size of `A` - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/transmute-padding-ice.rs:10:14 - | -LL | pub fn is_maybe_transmutable<Src, Dst>() - | --------------------- required by a bound in this function -LL | where -LL | Dst: BikeshedIntrinsicFrom< - | ______________^ -LL | | Src, -LL | | { Assume { alignment: true, lifetimes: true, safety: true, validity: true } }, -LL | | >, - | |_________^ required by this bound in `is_maybe_transmutable` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/uninhabited.rs b/tests/ui/transmutability/uninhabited.rs new file mode 100644 index 00000000000..b61b110f6a1 --- /dev/null +++ b/tests/ui/transmutability/uninhabited.rs @@ -0,0 +1,71 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, { + Assume { + alignment: true, + lifetimes: true, + safety: true, + validity: true, + } + }> + {} +} + +fn void() { + enum Void {} + + // 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::<Void, u128>(); + + assert::is_maybe_transmutable::<(), Void>(); //~ ERROR: cannot be safely transmuted +} + +// Non-ZST uninhabited types are, nonetheless, uninhabited. +fn yawning_void() { + enum Void {} + + struct YawningVoid(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. +fn distant_void() { + enum Void {} + + enum DistantVoid { + A(&'static Void) + } + + const _: () = { + assert!(std::mem::size_of::<DistantVoid>() == std::mem::size_of::<usize>()); + // Just to be sure the above constant actually evaluated: + assert!(false); //~ ERROR: evaluation of constant value failed + }; + + assert::is_maybe_transmutable::<DistantVoid, ()>(); + assert::is_maybe_transmutable::<DistantVoid, &'static Void>(); + assert::is_maybe_transmutable::<u128, DistantVoid>(); //~ ERROR: cannot be safely transmuted +} diff --git a/tests/ui/transmutability/uninhabited.stderr b/tests/ui/transmutability/uninhabited.stderr new file mode 100644 index 00000000000..60219b0f263 --- /dev/null +++ b/tests/ui/transmutability/uninhabited.stderr @@ -0,0 +1,86 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/uninhabited.rs:41:9 + | +LL | assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:41: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:65:9 + | +LL | assert!(false); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: false', $DIR/uninhabited.rs:65:9 + | + = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: `()` cannot be safely transmuted into `void::Void` + --> $DIR/uninhabited.rs:29:41 + | +LL | assert::is_maybe_transmutable::<(), Void>(); + | ^^^^ `void::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::Void` + --> $DIR/uninhabited.rs:49:41 + | +LL | assert::is_maybe_transmutable::<(), Void>(); + | ^^^^ `yawning_void::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]: `u128` cannot be safely transmuted into `DistantVoid` + --> $DIR/uninhabited.rs:70:43 + | +LL | assert::is_maybe_transmutable::<u128, DistantVoid>(); + | ^^^^^^^^^^^ at least one value of `u128` isn't a bit-valid value of `DistantVoid` + | +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: aborting due to 5 previous errors + +Some errors have detailed explanations: E0080, E0277. +For more information about an error, try `rustc --explain E0080`. diff --git a/tests/ui/transmutability/unions/repr/should_handle_align.rs b/tests/ui/transmutability/unions/repr/should_handle_align.rs index 8668cca3cb5..ba4e904e161 100644 --- a/tests/ui/transmutability/unions/repr/should_handle_align.rs +++ b/tests/ui/transmutability/unions/repr/should_handle_align.rs @@ -25,13 +25,13 @@ fn should_pad_explicitly_aligned_field() { #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 } - #[repr(C)] + #[repr(align(1))] pub union Uninit { a: (), b: V1u8, } - #[repr(C, align(2))] + #[repr(align(2))] pub union align_2 { a: V0u8, } diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/tests/ui/transmutability/unions/repr/should_handle_all.rs index 8495b0ea88f..85d48dd9b7f 100644 --- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.rs +++ b/tests/ui/transmutability/unions/repr/should_handle_all.rs @@ -1,7 +1,7 @@ -//! A struct must have a well-defined layout to participate in a transmutation. +//@ check-pass #![crate_type = "lib"] -#![feature(transmutability)] +#![feature(transmutability, transparent_unions)] #![allow(dead_code, incomplete_features, non_camel_case_types)] mod assert { @@ -20,17 +20,17 @@ mod assert { {} } -fn should_reject_repr_rust() +fn should_accept_repr_rust() { union repr_rust { a: u8 } - assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted - assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<repr_rust, ()>(); + assert::is_maybe_transmutable::<u128, repr_rust>(); } -fn should_accept_repr_C() +fn should_accept_repr_c() { #[repr(C)] union repr_c { @@ -41,3 +41,15 @@ fn should_accept_repr_C() assert::is_maybe_transmutable::<repr_c, ()>(); assert::is_maybe_transmutable::<u128, repr_c>(); } + + +fn should_accept_transparent() +{ + #[repr(transparent)] + union repr_transparent { + a: u8 + } + + assert::is_maybe_transmutable::<repr_transparent, ()>(); + assert::is_maybe_transmutable::<u128, repr_transparent>(); +} diff --git a/tests/ui/transmutability/unions/repr/should_handle_packed.rs b/tests/ui/transmutability/unions/repr/should_handle_packed.rs index 4af6c1d3a61..fc06eba4353 100644 --- a/tests/ui/transmutability/unions/repr/should_handle_packed.rs +++ b/tests/ui/transmutability/unions/repr/should_handle_packed.rs @@ -27,7 +27,6 @@ fn should_pad_explicitly_packed_field() { #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 } #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 } - #[repr(C)] pub union Uninit { a: (), b: V1u8, diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr deleted file mode 100644 index bec07f13103..00000000000 --- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr +++ /dev/null @@ -1,47 +0,0 @@ -error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` - --> $DIR/should_require_well_defined_layout.rs:29:48 - | -LL | assert::is_maybe_transmutable::<repr_rust, ()>(); - | ^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` - --> $DIR/should_require_well_defined_layout.rs:30:43 - | -LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ analyzing the transmutability of `should_reject_repr_rust::repr_rust` is not yet supported. - | -note: required by a bound in `is_maybe_transmutable` - --> $DIR/should_require_well_defined_layout.rs:12: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: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs b/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs deleted file mode 100644 index ae463b6ef5b..00000000000 --- a/tests/ui/type-alias-impl-trait/issue-53398-cyclic-types.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(type_alias_impl_trait)] - -//@ check-pass - -type Foo = impl Fn() -> Foo; - -fn foo() -> Foo { - foo -} - -fn main() {} diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr deleted file mode 100644 index 1c36fda4ae1..00000000000 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.current.stderr +++ /dev/null @@ -1,23 +0,0 @@ -note: no errors encountered even though delayed bugs were created - -note: those delayed bugs will now be shown as internal compiler errors - -error: internal compiler error: {OpaqueTypeKey { def_id: DefId(get_rpit::{opaque#0}), args: [] }: OpaqueTypeDecl { hidden_type: OpaqueHiddenType { span: no-location (#0), ty: Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }) } }} - | - = - - -error: internal compiler error: error performing ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: ProvePredicate { predicate: Binder { value: ProjectionPredicate(AliasTy { args: [FnDef(DefId(get_rpit), []), ()], def_id: DefId(ops::function::FnOnce::Output) }, Term::Ty(Alias(Opaque, AliasTy { args: [], def_id: DefId(Opaque::{opaque#0}) }))), bound_vars: [] } } } - --> $DIR/rpit_tait_equality_in_canonical_query.rs:32:5 - | -LL | query(get_rpit); - | ^^^^^^^^^^^^^^^ - | - - --> $DIR/rpit_tait_equality_in_canonical_query.rs:32:5 - | -LL | query(get_rpit); - | ^^^^^^^^^^^^^^^ - -query stack during panic: -end of query stack diff --git a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs index 7524cebf9e6..6f50703aca2 100644 --- a/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs +++ b/tests/ui/type-alias-impl-trait/rpit_tait_equality_in_canonical_query.rs @@ -8,17 +8,7 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] check-pass - -//@[current] known-bug: #108498 -//@[current] failure-status: 101 -//@[current] normalize-stderr-test: "DefId\(.*?\]::" -> "DefId(" -//@[current] normalize-stderr-test: "(?m)note: we would appreciate a bug report.*\n\n" -> "" -//@[current] normalize-stderr-test: "(?m)note: rustc.*running on.*\n\n" -> "" -//@[current] normalize-stderr-test: "(?m)note: compiler flags.*\n\n" -> "" -//@[current] normalize-stderr-test: "(?m)note: delayed at.*$" -> "" -//@[current] normalize-stderr-test: "(?m)^ *\d+: .*\n" -> "" -//@[current] normalize-stderr-test: "(?m)^ *at .*\n" -> "" +//@ check-pass #![feature(type_alias_impl_trait)] diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs index e5e7fb677ed..19986247d40 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.rs @@ -1,12 +1,10 @@ #![feature(type_alias_impl_trait)] +//@ known-bug: #109268 type Foo = impl Fn() -> Foo; -//~^ ERROR: unconstrained opaque type fn crash(x: Foo) -> Foo { x } -fn main() { - -} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr new file mode 100644 index 00000000000..ee8922b673e --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-1.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `<Foo as FnOnce<()>>::Output == Foo` + --> $DIR/type-alias-impl-trait-with-cycle-error-1.rs:6:21 + | +LL | fn crash(x: Foo) -> Foo { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs index 7c7a1b405bc..761cc83af51 100644 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.rs +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.rs @@ -1,11 +1,11 @@ #![feature(type_alias_impl_trait)] +//@ known-bug: #109268 pub trait Bar<T> { type Item; } type Foo = impl Bar<Foo, Item = Foo>; -//~^ ERROR: unconstrained opaque type fn crash(x: Foo) -> Foo { x diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr new file mode 100644 index 00000000000..3d0f1d30ca2 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-2.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `<Foo as Bar<Foo>>::Item == Foo` + --> $DIR/type-alias-impl-trait-with-cycle-error-2.rs:10:21 + | +LL | fn crash(x: Foo) -> Foo { + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs new file mode 100644 index 00000000000..52942afd639 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.rs @@ -0,0 +1,10 @@ +#![feature(type_alias_impl_trait)] +//@ known-bug: #109268 + +type Foo<'a> = impl Fn() -> Foo<'a>; + +fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> { + x +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr new file mode 100644 index 00000000000..675689bac42 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-3.stderr @@ -0,0 +1,9 @@ +error[E0275]: overflow evaluating the requirement `<Foo<'_> as FnOnce<()>>::Output == Foo<'a>` + --> $DIR/type-alias-impl-trait-with-cycle-error-3.rs:6:40 + | +LL | fn crash<'a>(_: &'a (), x: Foo<'a>) -> Foo<'a> { + | ^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs new file mode 100644 index 00000000000..e866b45a8e6 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.rs @@ -0,0 +1,16 @@ +#![feature(type_alias_impl_trait)] +//@ known-bug: trait-system-refactor-initiative#43 + +trait Id { + type Assoc; +} +impl<T> Id for T { + type Assoc = T; +} + +type Ty +where + Ty: Id<Assoc = Ty>, += impl Sized; +fn define() -> Ty {} +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr new file mode 100644 index 00000000000..aedb78bf5e7 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error-4.stderr @@ -0,0 +1,39 @@ +error[E0275]: overflow evaluating the requirement `Ty: Id` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:11:1 + | +LL | type Ty + | ^^^^^^^ + | +note: required by a bound on the type alias `Ty` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 + | +LL | Ty: Id<Assoc = Ty>, + | ^^^^^^^^^^^^^^ required by this bound + +error[E0275]: overflow evaluating the requirement `Ty: Id` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:19 + | +LL | fn define() -> Ty {} + | ^^ + | +note: required by a bound on the type alias `Ty` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 + | +LL | Ty: Id<Assoc = Ty>, + | ^^^^^^^^^^^^^^ required by this bound + +error[E0275]: overflow evaluating the requirement `Ty: Id` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:15:16 + | +LL | fn define() -> Ty {} + | ^^ + | +note: required by a bound on the type alias `Ty` + --> $DIR/type-alias-impl-trait-with-cycle-error-4.rs:13:9 + | +LL | Ty: Id<Assoc = Ty>, + | ^^^^^^^^^^^^^^ required by this bound + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr deleted file mode 100644 index 3d43fbe0dbc..00000000000 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-with-cycle-error.rs:3:12 - | -LL | type Foo = impl Fn() -> Foo; - | ^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module - -error: aborting due to 1 previous error - diff --git a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr b/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr deleted file mode 100644 index e2dc887989b..00000000000 --- a/tests/ui/type-alias-impl-trait/type-alias-impl-trait-with-cycle-error2.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: unconstrained opaque type - --> $DIR/type-alias-impl-trait-with-cycle-error2.rs:7:12 - | -LL | type Foo = impl Bar<Foo, Item = Foo>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `Foo` must be used in combination with a concrete type within the same module - -error: aborting due to 1 previous error - diff --git a/tests/ui/type/pattern_types/bad_pat.rs b/tests/ui/type/pattern_types/bad_pat.rs new file mode 100644 index 00000000000..8ad042eeba6 --- /dev/null +++ b/tests/ui/type/pattern_types/bad_pat.rs @@ -0,0 +1,14 @@ +#![feature(pattern_types)] +#![feature(core_pattern_types)] +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +type NonNullU32_2 = pattern_type!(u32 is 1..=); +//~^ ERROR: inclusive range with no end +type Positive2 = pattern_type!(i32 is 0..=); +//~^ ERROR: inclusive range with no end +type Wild = pattern_type!(() is _); +//~^ ERROR: wildcard patterns are not permitted for pattern types + +fn main() {} diff --git a/tests/ui/type/pattern_types/bad_pat.stderr b/tests/ui/type/pattern_types/bad_pat.stderr new file mode 100644 index 00000000000..4f0f0bc9742 --- /dev/null +++ b/tests/ui/type/pattern_types/bad_pat.stderr @@ -0,0 +1,25 @@ +error[E0586]: inclusive range with no end + --> $DIR/bad_pat.rs:7:43 + | +LL | type NonNullU32_2 = pattern_type!(u32 is 1..=); + | ^^^ help: use `..` instead + | + = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +error[E0586]: inclusive range with no end + --> $DIR/bad_pat.rs:9:40 + | +LL | type Positive2 = pattern_type!(i32 is 0..=); + | ^^^ help: use `..` instead + | + = note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`) + +error: "wildcard patterns are not permitted for pattern types" + --> $DIR/bad_pat.rs:11:33 + | +LL | type Wild = pattern_type!(() is _); + | ^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0586`. diff --git a/tests/ui/type/pattern_types/derives.noimpl.stderr b/tests/ui/type/pattern_types/derives.noimpl.stderr new file mode 100644 index 00000000000..9450e575344 --- /dev/null +++ b/tests/ui/type/pattern_types/derives.noimpl.stderr @@ -0,0 +1,14 @@ +error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + --> $DIR/derives.rs:14:20 + | +LL | #[derive(Clone, Copy, PartialEq)] + | --------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ + | + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs new file mode 100644 index 00000000000..b8b53e61102 --- /dev/null +++ b/tests/ui/type/pattern_types/derives.rs @@ -0,0 +1,20 @@ +//! Check that pattern types don't implement traits of their base automatically + +#![feature(pattern_types)] +#![feature(core_pattern_types)] +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +#[derive(Clone, Copy, PartialEq)] +#[repr(transparent)] +struct Nanoseconds(NanoI32); +//~^ ERROR: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + +type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999); + +fn main() { + let x = Nanoseconds(unsafe { std::mem::transmute(42) }); + let y = x.clone(); + if y == x {} +} diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr new file mode 100644 index 00000000000..1d4d3fc55c3 --- /dev/null +++ b/tests/ui/type/pattern_types/derives.stderr @@ -0,0 +1,14 @@ +error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999` + --> $DIR/derives.rs:11:20 + | +LL | #[derive(Clone, Copy, PartialEq)] + | --------- in this derive macro expansion +LL | #[repr(transparent)] +LL | struct Nanoseconds(NanoI32); + | ^^^^^^^ + | + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs new file mode 100644 index 00000000000..3c507a9669d --- /dev/null +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.rs @@ -0,0 +1,14 @@ +//@ compile-flags: -Zno-analysis + +use std::pat::pattern_type; + +type NonNullU32 = pattern_type!(u32 is 1..); +//~^ use of unstable library feature 'core_pattern_type' +type Percent = pattern_type!(u32 is 0..=100); +//~^ use of unstable library feature 'core_pattern_type' +type Negative = pattern_type!(i32 is ..=0); +//~^ use of unstable library feature 'core_pattern_type' +type Positive = pattern_type!(i32 is 0..); +//~^ use of unstable library feature 'core_pattern_type' +type Always = pattern_type!(Option<u32> is Some(_)); +//~^ use of unstable library feature 'core_pattern_type' diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr new file mode 100644 index 00000000000..6f74b89d224 --- /dev/null +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types.stderr @@ -0,0 +1,48 @@ +error[E0658]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:5:19 + | +LL | type NonNullU32 = pattern_type!(u32 is 1..); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:7:16 + | +LL | type Percent = pattern_type!(u32 is 0..=100); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:9:17 + | +LL | type Negative = pattern_type!(i32 is ..=0); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:11:17 + | +LL | type Positive = pattern_type!(i32 is 0..); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: use of unstable library feature 'core_pattern_type' + --> $DIR/feature-gate-pattern_types.rs:13:15 + | +LL | type Always = pattern_type!(Option<u32> is Some(_)); + | ^^^^^^^^^^^^ + | + = help: add `#![feature(core_pattern_type)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs new file mode 100644 index 00000000000..d7b3ea58e02 --- /dev/null +++ b/tests/ui/type/pattern_types/feature-gate-pattern_types2.rs @@ -0,0 +1,12 @@ +//@ compile-flags: -Zno-analysis +//@ check-pass + +#![feature(core_pattern_type)] + +use std::pat::pattern_type; + +type NonNullU32 = pattern_type!(u32 is 1..); +type Percent = pattern_type!(u32 is 0..=100); +type Negative = pattern_type!(i32 is ..=0); +type Positive = pattern_type!(i32 is 0..); +type Always = pattern_type!(Option<u32> is Some(_)); diff --git a/tests/ui/type/pattern_types/macros.active.stderr b/tests/ui/type/pattern_types/macros.active.stderr new file mode 100644 index 00000000000..002e944fe2e --- /dev/null +++ b/tests/ui/type/pattern_types/macros.active.stderr @@ -0,0 +1,10 @@ +error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments + --> $DIR/macros.rs:10:12 + | +LL | ($t:ty is $p:pat) => {}; + | ^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 1 previous error + diff --git a/tests/ui/type/pattern_types/macros.gated.stderr b/tests/ui/type/pattern_types/macros.gated.stderr new file mode 100644 index 00000000000..002e944fe2e --- /dev/null +++ b/tests/ui/type/pattern_types/macros.gated.stderr @@ -0,0 +1,10 @@ +error: `$t:ty` is followed by `is`, which is not allowed for `ty` fragments + --> $DIR/macros.rs:10:12 + | +LL | ($t:ty is $p:pat) => {}; + | ^^ not allowed after `ty` fragments + | + = note: allowed there are: `{`, `[`, `=>`, `,`, `>`, `=`, `:`, `;`, `|`, `as` or `where` + +error: aborting due to 1 previous error + diff --git a/tests/ui/type/pattern_types/macros.rs b/tests/ui/type/pattern_types/macros.rs new file mode 100644 index 00000000000..fd5fe257e8e --- /dev/null +++ b/tests/ui/type/pattern_types/macros.rs @@ -0,0 +1,15 @@ +//@ revisions: gated active + +#![cfg_attr(active, feature(pattern_types))] +#![allow(incomplete_features)] + +// Check that pattern types do not affect existing macros. +// They don't, because pattern types don't have surface syntax. + +macro_rules! foo { + ($t:ty is $p:pat) => {}; //~ ERROR `$t:ty` is followed by `is`, which is not allowed for `ty` fragments +} + +fn main() { + foo!(u32 is 1..) +} diff --git a/tests/ui/type/pattern_types/range_patterns.rs b/tests/ui/type/pattern_types/range_patterns.rs new file mode 100644 index 00000000000..d1fd055dbab --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns.rs @@ -0,0 +1,23 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//@ normalize-stderr-test "pref: Align\([1-8] bytes\)" -> "pref: $$SOME_ALIGN" + +use std::pat::pattern_type; + +#[rustc_layout(debug)] +type X = std::num::NonZeroU32; //~ ERROR layout_of +#[rustc_layout(debug)] +type Y = pattern_type!(u32 is 1..); //~ ERROR layout_of +#[rustc_layout(debug)] +type Z = Option<pattern_type!(u32 is 1..)>; //~ ERROR layout_of +#[rustc_layout(debug)] +type A = Option<std::num::NonZeroU32>; //~ ERROR layout_of +#[rustc_layout(debug)] +struct NonZeroU32New(pattern_type!(u32 is 1..)); //~ ERROR layout_of + +fn main() { + let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(42_u32) }; +} diff --git a/tests/ui/type/pattern_types/range_patterns.stderr b/tests/ui/type/pattern_types/range_patterns.stderr new file mode 100644 index 00000000000..8465e1b7ff2 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns.stderr @@ -0,0 +1,343 @@ +error: layout_of(NonZero<u32>) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:11:1 + | +LL | type X = std::num::NonZeroU32; + | ^^^^^^ + +error: layout_of((u32) is 1..=) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Primitive, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:13:1 + | +LL | type Y = pattern_type!(u32 is 1..); + | ^^^^^^ + +error: layout_of(Option<(u32) is 1..=>) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + tag_encoding: Niche { + untagged_variant: 1, + niche_variants: 0..=0, + niche_start: 0, + }, + tag_field: 0, + variants: [ + Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:15:1 + | +LL | type Z = Option<pattern_type!(u32 is 1..)>; + | ^^^^^^ + +error: layout_of(Option<NonZero<u32>>) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: None, + variants: Multiple { + tag: Initialized { + value: Int( + I32, + false, + ), + valid_range: (..=0) | (1..), + }, + tag_encoding: Niche { + untagged_variant: 1, + niche_variants: 0..=0, + niche_start: 0, + }, + tag_field: 0, + variants: [ + Layout { + size: Size(0 bytes), + align: AbiAndPrefAlign { + abi: Align(1 bytes), + pref: $SOME_ALIGN, + }, + abi: Aggregate { + sized: true, + }, + fields: Arbitrary { + offsets: [], + memory_index: [], + }, + largest_niche: None, + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(1 bytes), + }, + Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 1, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + }, + ], + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:17:1 + | +LL | type A = Option<std::num::NonZeroU32>; + | ^^^^^^ + +error: layout_of(NonZeroU32New) = Layout { + size: Size(4 bytes), + align: AbiAndPrefAlign { + abi: Align(4 bytes), + pref: $SOME_ALIGN, + }, + abi: Scalar( + Initialized { + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + fields: Arbitrary { + offsets: [ + Size(0 bytes), + ], + memory_index: [ + 0, + ], + }, + largest_niche: Some( + Niche { + offset: Size(0 bytes), + value: Int( + I32, + false, + ), + valid_range: 1..=4294967295, + }, + ), + variants: Single { + index: 0, + }, + max_repr_align: None, + unadjusted_abi_align: Align(4 bytes), + } + --> $DIR/range_patterns.rs:19:1 + | +LL | struct NonZeroU32New(pattern_type!(u32 is 1..)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs new file mode 100644 index 00000000000..9653a744c41 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.rs @@ -0,0 +1,30 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types can have traits implemented for them if +//! their base type is a local type. + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); + +impl Y { + //~^ ERROR cannot define inherent `impl` + fn foo() {} +} + +struct MyStruct<T>(T); + +impl MyStruct<Y> { + fn foo() {} +} + +struct Wrapper(Y); + +impl Wrapper { + fn foo() {} +} + +fn main() {} diff --git a/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr new file mode 100644 index 00000000000..784ebb0c9f0 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_inherent_impls.stderr @@ -0,0 +1,16 @@ +error[E0390]: cannot define inherent `impl` for primitive types outside of `core` + --> $DIR/range_patterns_inherent_impls.rs:13:1 + | +LL | impl Y { + | ^^^^^^ + | + = help: consider moving this inherent impl into `core` if possible +help: alternatively add `#[rustc_allow_incoherent_impl]` to the relevant impl items + --> $DIR/range_patterns_inherent_impls.rs:15:5 + | +LL | fn foo() {} + | ^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0390`. diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs new file mode 100644 index 00000000000..f8c9af86281 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls.rs @@ -0,0 +1,19 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types can have local traits +//! implemented for them. + +//@ check-pass + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); + +trait Trait {} + +impl Trait for Y {} + +fn main() {} diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs new file mode 100644 index 00000000000..acde4580c1b --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.rs @@ -0,0 +1,16 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types can have local traits +//! implemented for them. + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); + +impl Eq for Y {} +//~^ ERROR: only traits defined in the current crate can be implemented for arbitrary types + +fn main() {} diff --git a/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr new file mode 100644 index 00000000000..41f42455bde --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_trait_impls2.stderr @@ -0,0 +1,14 @@ +error[E0117]: only traits defined in the current crate can be implemented for arbitrary types + --> $DIR/range_patterns_trait_impls2.rs:13:1 + | +LL | impl Eq for Y {} + | ^^^^^^^^^^^^- + | | | + | | `(u32) is 1..=` is not defined in the current crate + | impl doesn't use only types from inside the current crate + | + = note: define and implement a trait or new type instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0117`. diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.rs b/tests/ui/type/pattern_types/range_patterns_unusable.rs new file mode 100644 index 00000000000..7cde44f4133 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable.rs @@ -0,0 +1,15 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! Some practical niche checks. + +use std::pat::pattern_type; + +type Z = Option<pattern_type!(u32 is 1..)>; + +fn main() { + let z: Z = Some(unsafe { std::mem::transmute(42_u32) }); + let _: Option<u32> = unsafe { std::mem::transmute(z) }; //~ ERROR: different sizes +} diff --git a/tests/ui/type/pattern_types/range_patterns_unusable.stderr b/tests/ui/type/pattern_types/range_patterns_unusable.stderr new file mode 100644 index 00000000000..aa0e592684b --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable.stderr @@ -0,0 +1,12 @@ +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types + --> $DIR/range_patterns_unusable.rs:14:35 + | +LL | let _: Option<u32> = unsafe { std::mem::transmute(z) }; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `Option<(u32) is 1..=>` (32 bits) + = note: target type: `Option<u32>` (64 bits) + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0512`. diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.rs b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs new file mode 100644 index 00000000000..bc1ab75429d --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.rs @@ -0,0 +1,16 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] + +//! check that pattern types don't have an `Add` impl. + +use std::pat::pattern_type; + +type Y = pattern_type!(u32 is 1..); +type Z = Option<pattern_type!(u32 is 1..)>; + +fn main() { + let x: Y = unsafe { std::mem::transmute(42_u32) }; + let x = x + 1_u32; //~ ERROR cannot add `u32` to `(u32) is 1..=` +} diff --git a/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr new file mode 100644 index 00000000000..e52d899a703 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_unusable_math.stderr @@ -0,0 +1,11 @@ +error[E0369]: cannot add `u32` to `(u32) is 1..=` + --> $DIR/range_patterns_unusable_math.rs:15:15 + | +LL | let x = x + 1_u32; + | - ^ ----- u32 + | | + | (u32) is 1..= + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/type/pattern_types/range_patterns_usage.rs b/tests/ui/type/pattern_types/range_patterns_usage.rs new file mode 100644 index 00000000000..7fe50423c51 --- /dev/null +++ b/tests/ui/type/pattern_types/range_patterns_usage.rs @@ -0,0 +1,26 @@ +#![feature(pattern_types, rustc_attrs)] +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] +#![allow(incomplete_features)] +//@ check-pass + +//! check that pattern types can actually be part of code that compiles successfully. + +use std::pat::pattern_type; + +type X = std::num::NonZeroU32; +type Y = pattern_type!(u32 is 1..); +type Z = Option<pattern_type!(u32 is 1..)>; +struct NonZeroU32New(pattern_type!(u32 is 1..)); + +fn main() { + let x: Y = unsafe { std::mem::transmute(42_u32) }; + let z: Z = Some(unsafe { std::mem::transmute(42_u32) }); + match z { + Some(y) => { + let _: Y = y; + } + None => {} + } + let x: X = unsafe { std::mem::transmute(x) }; +} diff --git a/tests/ui/type/pattern_types/unimplemented_pat.rs b/tests/ui/type/pattern_types/unimplemented_pat.rs new file mode 100644 index 00000000000..c02160ff58a --- /dev/null +++ b/tests/ui/type/pattern_types/unimplemented_pat.rs @@ -0,0 +1,15 @@ +//! This test ensures we do not ICE for unimplemented +//! patterns unless the feature gate is enabled. + +#![feature(core_pattern_type)] +#![feature(core_pattern_types)] + +use std::pat::pattern_type; + +type Always = pattern_type!(Option<u32> is Some(_)); +//~^ ERROR: pattern types are unstable + +type Binding = pattern_type!(Option<u32> is x); +//~^ ERROR: pattern types are unstable + +fn main() {} diff --git a/tests/ui/type/pattern_types/unimplemented_pat.stderr b/tests/ui/type/pattern_types/unimplemented_pat.stderr new file mode 100644 index 00000000000..481c6017dcc --- /dev/null +++ b/tests/ui/type/pattern_types/unimplemented_pat.stderr @@ -0,0 +1,23 @@ +error[E0658]: pattern types are unstable + --> $DIR/unimplemented_pat.rs:9:15 + | +LL | type Always = pattern_type!(Option<u32> is Some(_)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information + = help: add `#![feature(pattern_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: pattern types are unstable + --> $DIR/unimplemented_pat.rs:12:16 + | +LL | type Binding = pattern_type!(Option<u32> is x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #123646 <https://github.com/rust-lang/rust/issues/123646> for more information + = help: add `#![feature(pattern_types)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/typeck/remove-semi-but-confused-char.rs b/tests/ui/typeck/remove-semi-but-confused-char.rs new file mode 100644 index 00000000000..ccc6f59344c --- /dev/null +++ b/tests/ui/typeck/remove-semi-but-confused-char.rs @@ -0,0 +1,11 @@ +// Ensures our "remove semicolon" suggestion isn't hardcoded with a character width, +// in case it was accidentally mixed up with a greek question mark. +// issue: rust-lang/rust#123607 + +pub fn square(num: i32) -> i32 { + //~^ ERROR mismatched types + num * num; + //~^ ERROR unknown start of token +} + +fn main() {} diff --git a/tests/ui/typeck/remove-semi-but-confused-char.stderr b/tests/ui/typeck/remove-semi-but-confused-char.stderr new file mode 100644 index 00000000000..2d0b53a60ce --- /dev/null +++ b/tests/ui/typeck/remove-semi-but-confused-char.stderr @@ -0,0 +1,25 @@ +error: unknown start of token: \u{37e} + --> $DIR/remove-semi-but-confused-char.rs:7:14 + | +LL | num * num; + | ^ + | +help: Unicode character ';' (Greek Question Mark) looks like ';' (Semicolon), but it is not + | +LL | num * num; + | ~ + +error[E0308]: mismatched types + --> $DIR/remove-semi-but-confused-char.rs:5:28 + | +LL | pub fn square(num: i32) -> i32 { + | ------ ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +LL | +LL | num * num; + | - help: remove this semicolon to return this value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/issues/issue-23649-1.rs b/tests/ui/unsized/issue-23649-1.rs index 1c4252b40c6..1c4252b40c6 100644 --- a/tests/ui/issues/issue-23649-1.rs +++ b/tests/ui/unsized/issue-23649-1.rs diff --git a/tests/ui/issues/issue-23649-2.rs b/tests/ui/unsized/issue-23649-2.rs index 4a953de1768..4a953de1768 100644 --- a/tests/ui/issues/issue-23649-2.rs +++ b/tests/ui/unsized/issue-23649-2.rs diff --git a/tests/ui/issues/issue-23649-3.rs b/tests/ui/unsized/issue-23649-3.rs index 524055d99b4..524055d99b4 100644 --- a/tests/ui/issues/issue-23649-3.rs +++ b/tests/ui/unsized/issue-23649-3.rs diff --git a/tests/ui/version/version-info-flags.rs b/tests/ui/version/version-info-flags.rs new file mode 100644 index 00000000000..612113452c4 --- /dev/null +++ b/tests/ui/version/version-info-flags.rs @@ -0,0 +1,9 @@ +// Check that rustc accepts various version info flags. +//@ dont-check-compiler-stdout +//@ revisions: version verbose-version long-verbose-version +//@ check-pass +//@[version] compile-flags: -V +//@[verbose-version] compile-flags: -vV +//@[long-verbose-verison] compile-flags: --version --verbose + +fn main() {} diff --git a/triagebot.toml b/triagebot.toml index 927852f0ca2..b96225c4520 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -536,7 +536,12 @@ cc = ["@Nadrieril"] message = "Some changes occurred in exhaustiveness checking" cc = ["@Nadrieril"] +[mentions."compiler/rustc_session/src/config/cfg.rs"] +message = "Some changes occurred in cfg and check-cfg configuration" +cc = ["@Urgau"] + [mentions."compiler/rustc_lint/src/context/diagnostics/check_cfg.rs"] +message = "Some changes occurred in check-cfg diagnostics" cc = ["@Urgau"] [mentions."library/core/src/intrinsics/simd.rs"] |
